amazing maze

This commit is contained in:
2025-10-20 22:49:08 +03:00
parent 192a900a96
commit 3ff60a1cf4
9 changed files with 140 additions and 70 deletions
+14 -14
View File
@@ -205,23 +205,23 @@ export default {
// gameEngine.camera.scale.copy(l.camera.position)
}
let testGame1 = new Game1(gameEngine, '/static/textures/game1-test.jpg', 2, 3);
gameEngine.activeObjects.add(testGame1.object);
testGame1.object.position.set(0, 1, -15);
// let testGame1 = new Game1(gameEngine, '/static/textures/game1-test.jpg', 2, 3);
// gameEngine.activeObjects.add(testGame1.object);
// testGame1.object.position.set(0, 1, -15);
let testGame2 = new Game2(gameEngine, '/static/textures/game2-test.jpg', 3, 3);
gameEngine.activeObjects.add(testGame2.object);
testGame2.object.position.set(0, 1, 15);
testGame2.object.rotation.y += Math.PI;
// let testGame2 = new Game2(gameEngine, '/static/textures/game2-test.jpg', 3, 3);
// gameEngine.activeObjects.add(testGame2.object);
// testGame2.object.position.set(0, 1, 15);
// testGame2.object.rotation.y += Math.PI;
let testGame4 = new Game4(gameEngine, '/static/feathers-game.glb', 3, 4);
gameEngine.activeObjects.add(testGame4.object);
testGame4.object.position.set(15, 1, 5);
// let testGame4 = new Game4(gameEngine, '/static/feathers-game.glb', 3, 4);
// gameEngine.activeObjects.add(testGame4.object);
// testGame4.object.position.set(15, 1, 5);
let vp = new VideoPlayer(gameEngine, this.$refs.videoPlayer, 16, 9);
gameEngine.activeObjects.add(vp.object);
vp.object.position.set(37, 5.5, 15);
vp.object.rotation.y += -Math.PI/2;
// let vp = new VideoPlayer(gameEngine, this.$refs.videoPlayer, 16, 9);
// gameEngine.activeObjects.add(vp.object);
// vp.object.position.set(37, 5.5, 15);
// vp.object.rotation.y += -Math.PI/2;
let maze = new MazeQuizGame(gameEngine, {}, [
{s: 'Кое е най-голямото езеро в България', h: 'Wrong answer', a: true},
@@ -0,0 +1,34 @@
import { TextureLoader, MeshStandardMaterial, MeshBasicMaterial, PlaneGeometry, Mesh } from "three";
import { assignParams } from "@/lib/MeshUtils";
class ImageObject {
constructor(obj, context) {
var t = new TextureLoader().setPath(context.path).load(obj.value);
//t.encoding = sRGBEncoding;
var mp = {
map: t,
alphaTest: 0.5
};
if (obj.nm) {
mp.normalMap = new TextureLoader().setPath(context.path).load(obj.nm);
}
if (obj.em) {
mp.emissiveMap = new TextureLoader().setPath(context.path).load(obj.em);
}
if (obj.am) {
mp.alphaMap = new TextureLoader().setPath(context.path).load(obj.am);
}
obj.material && Object.assign(mp, obj.material);
let geo = new PlaneGeometry(context.wallSize * (obj.w || 1), context.wallSize * (obj.h || 1));
if (obj.uv) {
var uvAttribute = geo.attributes.uv;
for (var i = 0; i < uvAttribute.count; i++) {
uvAttribute.setXY(i, obj.uv[2 * i], obj.uv[2 * i + 1]);
}
}
this.object = new Mesh(geo, mp.metalness ? new MeshStandardMaterial(mp) : new MeshBasicMaterial(mp));
assignParams(this.object, obj);
}
}
export {ImageObject}
@@ -1,8 +1,7 @@
import { ImageObject } from "./ImageObject";
import { Hint } from "./Hint";
//import { Hint } from "./Hint";
import { Group, AnimationMixer, LoopPingPong, Vector3 } from "three";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { Utils } from "./Utils";
import { assignMaterial, assignParams } from "@/lib/MeshUtils";
import { Game1 } from "./PuzzleGame1";
import { Game2 } from "./PuzzleGame2";
// import { Game3 } from "./games/Game3";
@@ -10,6 +9,7 @@ import { Game4 } from "./PuzzleGame4";
// import { Game5 } from "./games/Game5";
// import { Game6 } from "./games/Game6";
import { TextObject } from "./TextObject";
import { ImageObject } from "./ImageObject";
const games = {Game1, Game2, Game4};
@@ -31,7 +31,7 @@ class InteractiveObject {
break;
case 'text':
let text = new TextObject(obj, context);
resolve(text.mesh);
resolve(text.object);
break;
case 'mesh':
mesh = obj.value;
@@ -39,12 +39,12 @@ class InteractiveObject {
break;
case 'image':
let imo = new ImageObject(obj, context);
mesh = imo.mesh;
mesh = imo.object;
resolve(mesh);
break;
case 'hint':
let hint = new Hint(obj, context);
mesh = hint.mesh;
mesh = hint.object;
resolve(mesh);
break;
case 'gltf':
@@ -58,7 +58,7 @@ class InteractiveObject {
// object.castShadow = true;
// object.receiveShadow = true;
});
Utils.assignMaterial(gltfObj, obj, context);
assignMaterial(gltfObj, obj, context);
if (gltf.animations && gltf.animations.length) {
let mixer = new AnimationMixer(gltfObj);
context.mixers.push(mixer);
@@ -71,7 +71,7 @@ class InteractiveObject {
break;
case 'asset':
mesh = context.assets[obj.value].clone();
Utils.assignMaterial(mesh, obj, context);
assignMaterial(mesh, obj, context);
resolve(mesh);
break;
case 'Game1':
@@ -81,7 +81,7 @@ class InteractiveObject {
case 'Game5':
case 'Game6':
var game = new games[obj.type](context, obj.args[0], obj.args[1], obj.args[2]);
mesh = game.game;
mesh = game.object;
mesh.game = game;
resolve(mesh);
break;
@@ -89,14 +89,14 @@ class InteractiveObject {
});
this.ready.then((mesh) => {
mesh.go = {};
let restriction;
if (!context.disableRestrictions && obj.restriction) {
restriction = {
type: 'deny',
a: [obj.room.localToWorld(new Vector3().fromArray(obj.restriction[0])), obj.room.localToWorld(new Vector3().fromArray(obj.restriction[1]))]
};
context.areas.push(restriction);
}
// let restriction;
// if (!context.disableRestrictions && obj.restriction) {
// restriction = {
// type: 'deny',
// a: [obj.room.localToWorld(new Vector3().fromArray(obj.restriction[0])), obj.room.localToWorld(new Vector3().fromArray(obj.restriction[1]))]
// };
// context.areas.push(restriction);
// }
mesh.go.finish = () => {
if (obj.finish) {
var f;
@@ -115,15 +115,15 @@ class InteractiveObject {
}
if (restriction) context.areas.splice(context.areas.indexOf(restriction), 1);
};
if (mesh.game) mesh.game.onfinish = mesh.go.finish;
Utils.assignParams(mesh, obj);
if (mesh.object) mesh.object.onfinish = mesh.go.finish;
assignParams(mesh, obj);
obj.animation && context.motionEngine.add({
o: mesh,
a: obj.animation.motion,
r: obj.animation.repeat,
t: obj.animation.duration || 1
});
this.mesh = mesh;
this.object = mesh;
});
}
}
@@ -1,6 +1,5 @@
import { Group, Vector3, Matrix4, Mesh, Quaternion, BoxGeometry } from 'three';
import * as BufferGeometryUtils from 'three/addons/utils/BufferGeometryUtils.js';
import { TextObject } from '../TextObject';
import { InteractiveObject } from '../InteractiveObject';
class MazeObject {
constructor(engine, def, params = {}){
@@ -14,7 +13,8 @@ class MazeObject {
context.wallSize = params.wallSize || 1.2*scale; //half
context.tubeSize = params.tubeSize || 1.2*scale;
context.wallDepth = params.wallDepth || 0*scale;
context.fontPath = params.fontPath || '/static/fonts/Jura-SemiBold.ttf';
context.fontPath = params.fontPath || '/static/fonts/Montserrat-Regular.ttf';
context.scale = scale;
this.context = context;
let _tf = {
@@ -29,7 +29,6 @@ class MazeObject {
};
let o = {};
let areas = [], mazeMeshes = [];
function addPhysics(matrix, position, size, placement = 'side'){
let quat = new Quaternion().setFromRotationMatrix(matrix);
@@ -58,7 +57,7 @@ class MazeObject {
let t = o.tunnel.clone();
t.position.set(0, 0, i * context.tubeSize);
def.matrix && t.applyMatrix4(def.matrix);
mazeMeshes.push(t);
root.add(t);
}
offsetZ = def.len * context.tubeSize;
//if (!def.len) offsetZ = -.275;
@@ -70,7 +69,6 @@ class MazeObject {
// console.log(offsetZ, room.localToWorld(new Vector3(context.tubeSize / 2, 0.6, offsetZ/2)))
let ofZ = def.len * context.tubeSize
addPhysics(def.matrix, [context.tubeSize / 2, 0.6, offsetZ/2], offsetZ)
addPhysics(def.matrix, [-context.tubeSize / 2, 0.6, offsetZ/2], offsetZ)
@@ -109,18 +107,19 @@ class MazeObject {
}
e.forEach(g => {
def.matrix && g.applyMatrix4(def.matrix);
mazeMeshes.push(g);
g.applyMatrix4(def.matrix);
root.add(g);
});
def.objects && def.objects.forEach(obj => {
def.objects && def.objects.forEach(async obj => {
obj.room = room;
// let go = new GameObject(obj, context);
let go = new TextObject(obj, context)
go.mesh.scale.multiplyScalar(scale)
go.mesh.position.multiply(new Vector3(scale, scale, context.wallSize))
go.mesh.applyMatrix4(def.matrix);
root.add(go.mesh);
let go = new InteractiveObject(obj, context)
await go.ready;
go.object.scale.multiplyScalar(context.wallSize)
go.object.position.multiplyScalar(context.wallSize)
go.object.applyMatrix4(def.matrix);
root.add(go.object);
// go.ready.then(mesh => {
// room.add(mesh);
// });
@@ -151,11 +150,11 @@ class MazeObject {
// console.log(e, o[e].geometry.boundingBox)
});
this.mazeObject(def, room);
mazeMeshes.forEach(mesh=>{
//let mesh = new Mesh(mg, o.tunnel.material)
root.add(mesh);
//engine.phy.add(mesh, 'fixed')
})
// mazeMeshes.forEach(mesh=>{
// //let mesh = new Mesh(mg, o.tunnel.material)
// root.add(mesh);
// //engine.phy.add(mesh, 'fixed')
// })
console.log(o.tunnel)
//scene.add(new Mesh(BufferGeometryUtils.mergeGeometries(mazeGeometries, false), o.tunnel.material));
@@ -23,7 +23,15 @@ class MazeQuizGame {
len,
objects:[
{
type: 'text', text: cq.s, position:[0,.44,len], rotation:[0,Math.PI, 0]
type: 'text', text: cq.s, position:[0,.4,len+.96], rotation:[0,Math.PI, 0]
},{
type: 'image', value: '/static/textures/arrow.png', position:[-.5,.44,len+.96], rotation:[0,Math.PI, 0], scale: [0.03, 0.03, 0.03]
},{
type: 'text', text: 'Вярно', position:[-.5,.3,len+.9], rotation:[0,Math.PI, 0]
},{
type: 'image', value: '/static/textures/arrow.png', position:[.5,.44,len+.96], rotation:[0,Math.PI, Math.PI], scale: [0.03, 0.03, 0.03]
},{
type: 'text', text: 'Невярно', position:[.5,.3,len+.9], rotation:[0,Math.PI, 0]
}
],
[lrv?'r':'l']:{
@@ -32,7 +40,7 @@ class MazeQuizGame {
len: lr,
objects:[
{
type: 'text', text: cq.h, position:[0,.44,lr], rotation:[0,Math.PI, 0]
type: 'text', text: cq.h, position:[0,.44,lr+.96], rotation:[0,Math.PI, 0]
}
]
}
@@ -1,13 +1,13 @@
import { MeshStandardMaterial, Color, Vector3 } from "three";
import { Text } from "troika-three-text";
import Utils from "@/lib/utils";
import { assignParams } from "@/lib/MeshUtils";
class TextObject {
constructor(obj, params) {
const txt = new Text();
// Set properties to configure:
txt.text = obj.text;
txt.fontSize = 0.022;
txt.fontSize = 0.033;
txt.lineHeight = 1.1;
txt.maxWidth = obj.width || params.wallSize * .73;
txt.textAlign = 'center';
@@ -16,18 +16,19 @@ class TextObject {
txt.anchorY = 'bottom';
txt.curveRadius = 0;
txt.outlineColor = 0xffffff;
txt.outlineWidth = '15%';
txt.outlineBlur = '50%';
Utils.assignMeshParams(txt, obj)
txt.outlineWidth = '1%';
txt.depthOffset = 0.1;
//txt.outlineBlur = '50%';
txt.color = new Color(0xffffff);
assignParams(txt, obj)
let m = new MeshStandardMaterial({
roughness: .73,
metalness: .37,
});
txt.material = m;
txt.color = new Color(0x0);
txt.sync();
this.txt = txt;
this.mesh = txt;
this.object = txt;
// if (obj.effect == 'distance') {
// let dstm = .8;
// var oldBR = txt.onBeforeRender;
+30
View File
@@ -0,0 +1,30 @@
import { TextureLoader } from "three";
function assignParams(mesh, params){
['scale', 'rotation', 'position'].forEach(p=>params[p] && mesh[p].fromArray(params[p]));
['visible', 'name'].forEach(p=>{
if (params[p]!==undefined) mesh[p] = params[p];
});
}
function assignMaterial(mesh, params, context){
if (params.name && params.material){
console.log(mesh)
//let mp = params.material.metalness ? new MeshStandardMaterial(params.material) : new MeshBasicMaterial(params.material)
Object.assign(mesh.material, params.material)
if (params.dm){
var dm = new TextureLoader().setPath(context.path).load(params.dm);
mesh.material.map = dm;
}
if (params.nm){
mesh.material.normalMap = new TextureLoader().setPath(context.path).load(params.nm);
}
if (params.em) {
mesh.material.emissiveMap = new TextureLoader().setPath(context.path).load(params.em);
}
//mesh.material = mp;
mesh.material.needsUpdate = true;
}
}
export { assignParams, assignMaterial }
+6 -1
View File
@@ -4,6 +4,7 @@ import { DRACOLoader } from 'three/examples/jsm/Addons.js';
import { OrbitControls } from 'three/examples/jsm/Addons.js';
//import { Controller as OrbitControls } from './3rd-party/phy/3TH/Controller.js';
import { ViewportGizmo } from "three-viewport-gizmo";
import Stats from 'three/examples/jsm/libs/stats.module';
//import { AnaglyphEffect } from './three/AnaglyphEffect';
import { AnaglyphEffect } from 'three/addons/effects/AnaglyphEffect.js';
import { StereoEffect } from 'three/addons/effects/StereoEffect.js';
@@ -23,7 +24,7 @@ class GameEngine {
this.opts = opts;
const gameEngine = this;
this.perspectiveCamera = new THREE.PerspectiveCamera(45, this.aspect, 0.01, 1000);
this.perspectiveCamera = new THREE.PerspectiveCamera(45, this.aspect, 0.01, 25);
this.raycaster = new THREE.Raycaster();
this.perspectiveCamera.position.set(0, 0, 10);
@@ -163,6 +164,9 @@ class GameEngine {
await this.initPhysics();
this.stats = new Stats();
document.body.appendChild(this.stats.dom);
if (opts.ar) {
renderer.xr.enabled = true;
document.body.appendChild(ARButton.createButton(renderer, {}));
@@ -569,6 +573,7 @@ class GameEngine {
} else {
this.renderer.render(scene, camera);
}
this.stats?.update()
}
}
-7
View File
@@ -54,11 +54,4 @@ export default {
rad2deg(rad){
return rad * 180 / Math.PI;
},
assignMeshParams(mesh, params){
['scale', 'rotation', 'position'].forEach(p=>params[p] && mesh[p].fromArray(params[p]));
['visible', 'name'].forEach(p=>{
if (params[p]!==undefined) mesh[p] = params[p];
});
},
}