This commit is contained in:
2026-03-18 22:00:21 +02:00
parent 691ec08e88
commit da326ddf96
4 changed files with 100 additions and 87 deletions
@@ -55,7 +55,6 @@ export default{
async obj(){ async obj(){
if (!this.obj) return; if (!this.obj) return;
gameEngine = new GameEngine(); gameEngine = new GameEngine();
this.gameEngine = gameEngine;
await gameEngine.init(this.$refs.target, { await gameEngine.init(this.$refs.target, {
gizmo: true, gizmo: true,
xr: true, xr: true,
@@ -56,14 +56,6 @@ export default {
renderType: 'ST', renderType: 'ST',
cameraType: 'perspective', 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);
}
} }
} }
</script> </script>
+90 -76
View File
@@ -263,31 +263,86 @@ class GameEngine extends EventManager{
}).bind(this) }).bind(this)
renderer.domElement.addEventListener('wheel', this._wheelEvent) renderer.domElement.addEventListener('wheel', this._wheelEvent)
GameEngine.ktxLoader.detectSupport(renderer); GameEngine.ktxLoader.detectSupport(renderer);
} }
initXr() { 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); 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.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); 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.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(); const controllerModelFactory = new XRControllerModelFactory();
@@ -307,6 +362,16 @@ class GameEngine extends EventManager{
this.xrCamera = this.renderer.xr.getCamera(); 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() { initCameraPivot() {
this.cameraWorld = new THREE.Group(); this.cameraWorld = new THREE.Group();
this.cameraRig = 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; $ = THREE;
async load(url, path = assetPath, progress) { async load(url, path = assetPath, progress) {
@@ -658,8 +665,14 @@ class GameEngine extends EventManager{
clearObject(o){ clearObject(o){
let disposables = [] let disposables = []
o.traverse(object => { o.traverse(object => {
if (!object.isMesh) return; if (object.isMesh) {
disposables.push(object); disposables.push(object);
}
if (object.isLight){
object.shadow?.map?.dispose();
object.shadow?.dispose();
object.dispose();
}
}); });
disposables.forEach(object=>{ disposables.forEach(object=>{
object.removeFromParent(); object.removeFromParent();
@@ -720,6 +733,7 @@ class GameEngine extends EventManager{
dispose(){ dispose(){
this.stop(); this.stop();
this.clearScene(); this.clearScene();
this.disposeXr();
this.renderer.dispose(); this.renderer.dispose();
this.pmremGenerator.dispose(); this.pmremGenerator.dispose();
this.arBtn?.remove(); this.arBtn?.remove();
+10 -2
View File
@@ -8,7 +8,7 @@ let engine = null;
export default { export default {
async mounted(){ async mounted(){
this.engine = engine = new GameEngine(); engine = new GameEngine();
await engine.init(this.$refs.target, { await engine.init(this.$refs.target, {
xr: true, xr: true,
gizmo: this.env == 'GameDesigner', gizmo: this.env == 'GameDesigner',
@@ -32,7 +32,8 @@ export default {
window.removeEventListener('resize', this.resize); window.removeEventListener('resize', this.resize);
engine.tm?.setGame(null); engine.tm?.setGame(null);
engine.dispose(); engine.dispose();
this.debug('Disposed scene', engine.renderer.info.memory) this.debug('Disposed scene', engine.renderer.info.memory);
engine = null;
}, },
computed:{ computed:{
@@ -307,6 +308,13 @@ export default {
async fullScreen(){ async fullScreen(){
await engine.renderer.domElement.requestFullscreen() 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);
} }
} }
} }