video player as interactive object + move to HUD

This commit is contained in:
2025-11-03 14:07:17 +02:00
parent d8618c69f4
commit b1e27301b4
7 changed files with 134 additions and 52 deletions
@@ -65,11 +65,8 @@
<script>
import { GameEngine } from '@/lib/GameEngine';
import GameEnvironmentMixin from '@/mixins/GameEnvironmentMixin';
let gameEngine = null;
export default {
mixins: [GameEnvironmentMixin],
props:{
@@ -52,12 +52,7 @@
<script>
import { GameEngine } from '@/lib/GameEngine';
import { Hero } from '@/lib/Hero';
import { Grass } from '@/components/InteractiveObjects/Grass';
import { VideoPlayer } from '@/components/InteractiveObjects/VideoPlayer';
import { useAppStore } from '@/stores/app';
import { MazeQuizGame } from '../InteractiveObjects/MazeQuizGame/MazeQuizGame';
import GameEnvironmentMixin from '@/mixins/GameEnvironmentMixin';
@@ -10,6 +10,7 @@ import { PuzzleGame4 } from "./PuzzleGame4";
// import { Game6 } from "./games/Game6";
import { TextObject } from "./TextObject";
import { ImageObject } from "./ImageObject";
import { VideoPlayer } from "./VideoPlayer";
const games = {PuzzleGame1, PuzzleGame2, PuzzleGame4};
@@ -18,7 +19,7 @@ class InteractiveObject {
this.name = obj.name;
this.ready = new Promise((resolve, reject) => {
let mesh;
switch (obj.type) {
switch (obj.id) {
case 'group':
mesh = new Group();
obj.group.forEach(g => {
@@ -48,7 +49,7 @@ class InteractiveObject {
resolve(mesh);
break;
case 'gltf':
console.log('loadingg', obj.value)
//console.log('loadingg', obj.value)
new GLTFLoader().load(obj.value, (gltf) => {
let gltfObj = gltf.scene;
gltf.scene.traverse(function (object) {
@@ -81,11 +82,15 @@ class InteractiveObject {
case 'PuzzleGame4':
case 'PuzzleGame5':
case 'PuzzleGame6':
var game = new games[obj.type](context, obj.args[0], obj.args[1], obj.args[2]);
let game = new games[obj.type](context, obj.args[0], obj.args[1], obj.args[2]);
mesh = game.object;
mesh.game = game;
resolve(mesh);
break;
case 'VideoPlayer':
let vp = new VideoPlayer(context, `/asset/default/${obj.$go.asset.name}`);
vp.ready.then(resolve);
break;
}
});
this.ready.then((mesh) => {
@@ -137,6 +142,6 @@ const InteractiveObjectTypes = [
}, {
id: 'VideoPlayer', name: 'Video Player'
}
]
];
export { InteractiveObject, InteractiveObjectTypes }
@@ -2,28 +2,78 @@ import * as THREE from 'three';
class VideoPlayer {
constructor(context, video, w, h){
let geometry = new THREE.PlaneGeometry( w, h );
let map = new THREE.VideoTexture( video );
map.colorSpace = THREE.SRGBColorSpace;
let material = new THREE.MeshStandardMaterial( {
color: 0xffffff,
map,
transparent: true,
opacity: 0.5,
} );
let plane = new THREE.Mesh( geometry, material );
this.object = plane;
constructor(context, src){
let vi, plane, data;
context.clickable.add(plane, ()=>{
material.opacity = 0.9
if (video.paused){
video.play();
}else{
video.pause();
}
});
this.ready = new Promise((resolve, reject)=>{
vi = document.createElement('video');
vi.src = src;
vi.addEventListener('loadedmetadata', ()=>{
this.aspect = vi.videoWidth / vi.videoHeight;
let geometry = new THREE.PlaneGeometry( this.aspect, 1 );
let map = new THREE.VideoTexture( vi );
map.colorSpace = THREE.SRGBColorSpace;
let material = new THREE.MeshStandardMaterial( {
color: 0xffffff,
map,
transparent: true,
opacity: 0.5,
side: THREE.DoubleSide
} );
plane = new THREE.Mesh( geometry, material );
this.object = plane;
context.clickable.add(plane, ()=>{
material.opacity = 1
if (vi.paused){
vi.play();
}else{
vi.pause();
}
});
resolve(plane);
})
vi.addEventListener('play', ()=>{
if (context.dashboard?.active){
//console.log(plane);
// plane.matrix.multiply(context.dashboard.group.matrix)
// plane.applyMatrix4(plane.matrix)
// let m1 = plane.matrix.clone(), m2 = context.dashboard.group.matrix.clone();
// let m = m1.premultiply(m2);
data = {
parent: plane.parent,
location: {
position: plane.position.clone(),
quaternion: plane.quaternion.clone(),
scale: plane.scale.clone()
}
}
console.log(data.location)
context.dashboard.group.attach(plane);
//plane.applyMatrix4(m.invert())
context.motionQueue.add({
o: plane,
a: {
rotation: { x:0, y:0, z:0 },
position: { x:0, y:0, z:-0.25 },
scale: { x: 1, y:1, z:1 }
},
t: 1
})
}
})
vi.addEventListener('pause', ()=>{
data.parent.attach(plane);
context.motionQueue.add({
o: plane,
a: data.location,
t: 1
})
})
})
}
}
export {VideoPlayer}
export { VideoPlayer }
+18
View File
@@ -29,6 +29,8 @@ class DashBoard {
})
const dash = new Group();
this.group = dash;
dash.visible = false;
const dashGeometry = new PlaneGeometry(engine.aspect, 1);
const dashMesh = new Mesh(dashGeometry, new MeshStandardMaterial({
@@ -81,9 +83,25 @@ class DashBoard {
progressCylinder.position.x = padLeft - engine.aspect/2 + progressCylinder.scale.y/2
}
this.enable = ()=>{
dash.visible = true;
}
this.disable = ()=>{
dash.visible = false;
}
this.createProgressBar();
this.update();
}
get active(){
return this.group.visible;
}
set active(v){
this.group.visible = v;
}
}
export { DashBoard };
+6 -3
View File
@@ -14,6 +14,7 @@ import { XRControllerModelFactory } from 'three/addons/webxr/XRControllerModelFa
import { Physics } from './Physics.js';
import { Clickable } from './Clickable.js';
import { DashBoard } from './Dashboard.js';
import { MotionEngine } from './MotionEngine.js';
class GameEngine extends THREE.EventDispatcher{
async init(domNode, opts = {}) {
@@ -99,6 +100,8 @@ class GameEngine extends THREE.EventDispatcher{
const dashboard = new DashBoard(this);
this.dashboard = dashboard;
this.motionQueue = new MotionEngine();
this.activeObjects = new THREE.Group();
scene.add(this.activeObjects);
@@ -129,8 +132,8 @@ class GameEngine extends THREE.EventDispatcher{
gameEngine.hero?.update();
gameEngine.mixers.forEach(m => m.update(delta));
gameEngine.handleXrAction(gameEngine, delta)
gameEngine.dispatchEvent({type: 'beforeRender'})
this.motionQueue.update();
gameEngine.render(scene, gameEngine.camera);
if (!renderer.xr.isPresenting) {
@@ -140,7 +143,7 @@ class GameEngine extends THREE.EventDispatcher{
// dashboard.render();
// renderer.autoClear = true;
}
renderer.setAnimationLoop(animate);
renderer.setAnimationLoop(animate.bind(this));
const mixer = new THREE.AnimationMixer(this.scene);
const clock = new THREE.Clock();
@@ -162,7 +165,7 @@ class GameEngine extends THREE.EventDispatcher{
// scene.background = bck; //new THREE.Color(0.7,0.7,0.7);
scene.environment = texture;
scene.background = new THREE.Color(1, 1, 1);
console.log('GameEngine started')
//console.log('GameEngine started')
renderer.domElement.addEventListener('wheel', (event) => {
gameEngine.camera.zoom -= event.deltaY / 1000;
gameEngine.camera.zoom = Math.max(gameEngine.camera.zoom, .4);
+30 -16
View File
@@ -1,3 +1,4 @@
import { InteractiveObject } from '@/components/InteractiveObjects/InteractiveObject';
import { GameEngine } from '@/lib/GameEngine';
import { Hero } from '@/lib/Hero';
let gameEngine = null;
@@ -13,8 +14,12 @@ export default {
designMode: this.env == 'GameDesigner',
depthSense: this.env == 'GameDesigner' ? false : this.store.prefs.xr.depthSense
});
gameEngine.scene.add(gameEngine.transformControls.getHelper());
//gameEngine.scene.add(new gameEngine.$.GridHelper(100,100));
if (this.env == 'GameDesigner'){
gameEngine.scene.add(gameEngine.transformControls.getHelper());
}else{
gameEngine.dashboard.enable();
}
this.resize();
//gameEngine.setCamera(gameEngine.orthographicCamera)
//gameEngine.setCameraOrthographic();
@@ -63,10 +68,11 @@ export default {
await this.loadScenario()
},
currentObject(n){
gameEngine.transformControls.attach(n.__o);
gameEngine.gizmo.target = n.__o.position;
//gameEngine.camera.lookAt(n.__o.position)
gameEngine.camera.updateProjectionMatrix()
if (this.env == 'GameDesigner'){
gameEngine.transformControls.attach(n.__o);
gameEngine.gizmo.target = n.__o.position;
gameEngine.camera.updateProjectionMatrix()
}
},
renderType(v){
gameEngine.renderType = v;
@@ -124,7 +130,11 @@ export default {
}
for (let i of this.scene.data.items || []) {
if (i.data.io){
i.data.$io = new InteractiveObject(i.data.io, gameEngine)
i.data.$io.ready.then(o=>{
this.setObjectAttributes(l, i.data, { scene: o }, 1);
gameEngine.activeObjects.add(o);
})
}else{
let gltf = await gameEngine.load(`/asset/default/${i.data.$go.asset.name}`);
this.setObjectAttributes(l, i.data, gltf, 1);
@@ -156,17 +166,21 @@ export default {
this.pointerDownTime = performance.now();
},
targetClick(e){
if (performance.now() - this.pointerDownTime < 200){
let intersects = gameEngine.intersect(e, this.$refs.target, gameEngine.activeObjects.children, true);
//console.log(intersects)
if (intersects.length){
//console.log('attaching controls to', intersects[0].object)
//gameEngine.transformControls.attach(intersects[0].object);
console.log(this.sceneObjects[intersects[0].object.__pn_id])
this.objectsList[0] = this.sceneObjects[intersects[0].object.__pn_id]
}else{
gameEngine.transformControls.detach();
if (this.env == 'GameDesigner'){
if (performance.now() - this.pointerDownTime < 200){
let intersects = gameEngine.intersect(e, this.$refs.target, gameEngine.activeObjects.children, true);
//console.log(intersects)
if (intersects.length){
//console.log('attaching controls to', intersects[0].object)
//gameEngine.transformControls.attach(intersects[0].object);
//console.log(this.sceneObjects[intersects[0].object.__pn_id])
this.objectsList[0] = this.sceneObjects[intersects[0].object.__pn_id]
}else{
gameEngine.transformControls.detach();
}
}
}else{
gameEngine.onClick(e, this.$refs.target);
}
},