refactor
This commit is contained in:
@@ -54,11 +54,11 @@
|
||||
|
||||
import { GameEngine } from '@/lib/GameEngine';
|
||||
import { Hero } from '@/lib/Hero';
|
||||
import { Game1 } from '@/lib/interactive-objects/Game1';
|
||||
import { Game2 } from '@/lib/interactive-objects/Game2';
|
||||
import { Game4 } from '@/lib/interactive-objects/Game4';
|
||||
import { Grass } from '@/lib/interactive-objects/Grass';
|
||||
import { VideoPlayer } from '@/lib/interactive-objects/VideoPlayer';
|
||||
import { Game1 } from '@/components/InteractiveObjects/PuzzleGame1';
|
||||
import { Game2 } from '@/components/InteractiveObjects/PuzzleGame2';
|
||||
import { Game4 } from '@/components/InteractiveObjects/PuzzleGame4';
|
||||
import { Grass } from '@/components/InteractiveObjects/Grass';
|
||||
import { VideoPlayer } from '@/components/InteractiveObjects/VideoPlayer';
|
||||
import { useAppStore } from '@/stores/app';
|
||||
|
||||
const store = useAppStore();
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
import {
|
||||
Matrix4,
|
||||
Mesh,
|
||||
PlaneGeometry,
|
||||
MeshPhongMaterial,
|
||||
Vector3,
|
||||
TextureLoader
|
||||
} from 'three';
|
||||
|
||||
import * as BufferGeometryUtils from 'three/addons/utils/BufferGeometryUtils.js';
|
||||
|
||||
class Grass {
|
||||
constructor(positions, texture, x, y) {
|
||||
return new Promise((resolve, reject) => {
|
||||
var tLoader = new TextureLoader();
|
||||
tLoader.load(texture, (t) => {
|
||||
//t.encoding = sRGBEncoding;
|
||||
// create the initial geometry
|
||||
var geometry = new PlaneGeometry(x || 1, y || 1);
|
||||
var material = new MeshPhongMaterial({
|
||||
map: t,
|
||||
alphaTest: .5,
|
||||
});
|
||||
geometry.applyMatrix4(new Matrix4().makeTranslation(0, geometry.parameters.height / 2, 0));
|
||||
geometry.normalizeNormals();
|
||||
|
||||
var arr = [];
|
||||
for (var i = 0; i < positions.length; i++) {
|
||||
var position = positions[i];
|
||||
var baseAngle = Math.PI * 2 * Math.random();
|
||||
|
||||
var nPlanes = 2;
|
||||
for (var j = 0; j < nPlanes; j++) {
|
||||
var angle = baseAngle + j * Math.PI / nPlanes;
|
||||
var gg = geometry.clone();
|
||||
gg.rotateY(angle);
|
||||
gg.translate(position.x, position.y, position.z);
|
||||
arr.push(gg);
|
||||
|
||||
var gg = geometry.clone();
|
||||
gg.rotateY(angle + Math.PI);
|
||||
gg.translate(position.x, position.y, position.z);
|
||||
arr.push(gg);
|
||||
}
|
||||
}
|
||||
var mesh = new Mesh(BufferGeometryUtils.mergeGeometries(arr, false), material);
|
||||
resolve(mesh);
|
||||
arr.forEach(g => g.dispose());
|
||||
});
|
||||
});
|
||||
}
|
||||
static positions(count, x, z) {
|
||||
var positions = new Array(count);
|
||||
for (var i = 0; i < count; i++) {
|
||||
var position = new Vector3();
|
||||
position.x = (Math.random() - 0.5) * x;
|
||||
position.z = (Math.random() - 0.5) * z;
|
||||
positions[i] = position;
|
||||
}
|
||||
return positions;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export { Grass }
|
||||
@@ -0,0 +1,96 @@
|
||||
import { BoxGeometry, Mesh, MeshBasicMaterial, Group } from 'three';
|
||||
import { TextureLoader } from 'three/src/loaders/TextureLoader';
|
||||
import { MotionEngine } from '../../lib/MotionEngine';
|
||||
|
||||
class Game1 {
|
||||
constructor(context, image, w, h) {
|
||||
this.game = new Group();
|
||||
const aq = new MotionEngine();
|
||||
const pr = [[0, -1], [0, 1], [1, 0], [-1, 0], [0, 0], [0, 2]];
|
||||
let d = 1.2;
|
||||
|
||||
let bm = new BoxGeometry(1, 1, 1);
|
||||
let uv = bm.getAttribute('uv');
|
||||
|
||||
for (let i = 0; i < 6; i++) {
|
||||
let s = [(i % w) / w, (i % h) / h];
|
||||
//top left
|
||||
uv.array[8 * i] = s[0];
|
||||
uv.array[8 * i + 1] = s[1] + 1 / h;
|
||||
//top right
|
||||
uv.array[8 * i + 2] = s[0] + 1 / w;
|
||||
uv.array[8 * i + 3] = s[1] + 1 / h;
|
||||
//bottom left
|
||||
uv.array[8 * i + 4] = s[0];
|
||||
uv.array[8 * i + 5] = s[1];
|
||||
//bottom right
|
||||
uv.array[8 * i + 6] = s[0] + 1 / w;
|
||||
uv.array[8 * i + 7] = s[1];
|
||||
}
|
||||
|
||||
let material = new MeshBasicMaterial({
|
||||
map: new TextureLoader().load(image)
|
||||
});
|
||||
//material.map.encoding = sRGBEncoding;
|
||||
|
||||
for (let i = 0; i < 6; i++) {
|
||||
let b = bm.clone();
|
||||
let mesh = new Mesh(b, material);
|
||||
mesh.position.set((i % w) * d, (i % h) * d, 0);
|
||||
let ri;
|
||||
do {
|
||||
ri = Math.floor(Math.random() * 6);
|
||||
} while (ri == this.game.children.length);
|
||||
mesh.rotation.set(pr[ri][0] * Math.PI / 2, pr[ri][1] * Math.PI / 2, 0);
|
||||
mesh._ri = ri;
|
||||
this.game.add(mesh);
|
||||
}
|
||||
|
||||
this.game.children[0].onBeforeRender = () => {
|
||||
this.update();
|
||||
};
|
||||
|
||||
var check = () => {
|
||||
if (!this.game.children.length) return false;
|
||||
let i = 0;
|
||||
for (let c of this.game.children) {
|
||||
if (Math.abs(c.rotation.x - pr[i][0] * Math.PI / 2) > 0.0001 || Math.abs(c.rotation.y - pr[i][1] * Math.PI / 2) > 0.0001) return false;
|
||||
i++;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
let clickFn = (i) => {
|
||||
if (!this.done && !aq.isActive(i.object)) {
|
||||
i.object._ri = (i.object._ri + 1) % 6;
|
||||
aq.add({
|
||||
o: i.object,
|
||||
a: { rotation: { x: pr[i.object._ri][0] * Math.PI / 2, y: pr[i.object._ri][1] * Math.PI / 2 } },
|
||||
t: .5
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
this.game.children.forEach(c => {
|
||||
context.clickable.add(c, clickFn);
|
||||
});
|
||||
|
||||
this.update = () => {
|
||||
aq.update();
|
||||
if (aq.isIdle() && !this.done && check()) {
|
||||
this.done = true;
|
||||
this.game.children.forEach((c, i) => {
|
||||
aq.add({
|
||||
o: c,
|
||||
a: { position: { x: i % w, y: i % h } },
|
||||
t: 1,
|
||||
f: i == 0 && this.onfinish
|
||||
});
|
||||
});
|
||||
//context.dashboard.addPoints(10);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export {Game1}
|
||||
@@ -0,0 +1,146 @@
|
||||
import { BoxGeometry, Mesh, MeshBasicMaterial, Group } from 'three';
|
||||
import { TextureLoader } from 'three/src/loaders/TextureLoader';
|
||||
import { MotionEngine } from '../../lib/MotionEngine';
|
||||
|
||||
class Game2 {
|
||||
constructor(context, image, w, h) {
|
||||
const texture = new TextureLoader().load(image);
|
||||
//texture.encoding = sRGBEncoding;
|
||||
const material = new MeshBasicMaterial({
|
||||
map: texture
|
||||
});
|
||||
const aq = new MotionEngine();
|
||||
const m2 = new MeshBasicMaterial({
|
||||
map: texture,
|
||||
transparent: true,
|
||||
opacity: 0.37
|
||||
});
|
||||
let last, lidx = w - 1;
|
||||
|
||||
this.game = new Group();
|
||||
let d = 1.2, p = [];
|
||||
|
||||
function check() {
|
||||
if (p.length) {
|
||||
for (let i = 0; i < p.length; i++) {
|
||||
if (p[i] != i) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function xch(x, y) {
|
||||
let temp = p[x];
|
||||
p[x] = p[y];
|
||||
p[y] = temp;
|
||||
}
|
||||
|
||||
this.shuffle = function () {
|
||||
function getMoves() {
|
||||
let m = [], pl = p[lidx];
|
||||
let xl = pl % w, yl = ~~(pl / h);
|
||||
if (xl > 0) m.push(p.indexOf(pl - 1));
|
||||
if (xl < w - 1) m.push(p.indexOf(pl + 1));
|
||||
if (yl > 0) m.push(p.indexOf(pl - w));
|
||||
if (yl < h - 1) m.push(p.indexOf(pl + w));
|
||||
return m;
|
||||
}
|
||||
for (let i = 0; i < w * h; i++) {
|
||||
p[i] = i;
|
||||
}
|
||||
|
||||
for (let iter = 0; iter < 73 * w * h; iter++) {
|
||||
let m = getMoves();
|
||||
xch(m[Math.floor(Math.random() * m.length)], lidx);
|
||||
}
|
||||
// while (p.length<9){
|
||||
// let n = Math.floor(Math.random()*9);
|
||||
// if (p.indexOf(n) == -1) p.push(n);
|
||||
// }
|
||||
p.forEach((e, i) => {
|
||||
let x = e % w, y = ~~(e / h);
|
||||
this.game.children[i].position.set(x * d, y * d, 0);
|
||||
});
|
||||
};
|
||||
|
||||
for (let i = 0; i < w * h; i++) {
|
||||
let x = i % w, xp = x / w;
|
||||
let y = ~~(i / h), yp = y / h;
|
||||
let bg = new BoxGeometry(1, 1, 1);
|
||||
let uv = bg.getAttribute('uv');
|
||||
for (let k = 0; k < 6; k++) {
|
||||
//top left
|
||||
uv.array[8 * k] = xp;
|
||||
uv.array[8 * k + 1] = yp + 1 / h;
|
||||
//top right
|
||||
uv.array[8 * k + 2] = xp + 1 / w;
|
||||
uv.array[8 * k + 3] = yp + 1 / h;
|
||||
//bottom left
|
||||
uv.array[8 * k + 4] = xp;
|
||||
uv.array[8 * k + 5] = yp;
|
||||
//bottom right
|
||||
uv.array[8 * k + 6] = xp + 1 / w;
|
||||
uv.array[8 * k + 7] = yp;
|
||||
}
|
||||
let mesh = new Mesh(bg, i != lidx ? material : m2);
|
||||
mesh.position.set(x * d, y * d, 0);
|
||||
this.game.add(mesh);
|
||||
}
|
||||
last = this.game.children[lidx];
|
||||
|
||||
this.game.children[0].onBeforeRender = () => {
|
||||
this.update();
|
||||
};
|
||||
|
||||
this.shuffle();
|
||||
|
||||
let clickFn = (i) => {
|
||||
if (!this.done && !aq.isActive(i.object)) {
|
||||
let idx = this.game.children.indexOf(i.object);
|
||||
if (idx == lidx) return; //we ignore the empty cell
|
||||
let xc = p[idx] % w, yc = ~~(p[idx] / h);
|
||||
let xl = p[lidx] % w, yl = ~~(p[lidx] / h);
|
||||
if (Math.abs(xc - xl) + Math.abs(yc - yl) == 1) {
|
||||
aq.add({
|
||||
o: i.object,
|
||||
a: { position: { x: (xl - xc) * d, y: (yl - yc) * d } },
|
||||
t: .3,
|
||||
m: 'offset'
|
||||
});
|
||||
aq.add({
|
||||
o: last,
|
||||
a: { position: { x: (xc - xl) * d, y: (yc - yl) * d } },
|
||||
t: .3,
|
||||
m: 'offset'
|
||||
});
|
||||
xch(idx, lidx);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.game.children.forEach(c => {
|
||||
context.clickable.add(c, clickFn);
|
||||
});
|
||||
|
||||
this.update = () => {
|
||||
aq.update();
|
||||
if (aq.isIdle() && !this.done && check()) {
|
||||
this.done = true;
|
||||
this.game.children.forEach((c, i) => {
|
||||
last.material = material;
|
||||
aq.add({
|
||||
o: c,
|
||||
a: { position: { x: i % w, y: ~~(i / h) } },
|
||||
t: 1,
|
||||
f: i == 0 && this.onfinish
|
||||
});
|
||||
});
|
||||
//context.dashboard.addPoints(10);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
export { Game2 };
|
||||
@@ -0,0 +1,124 @@
|
||||
import { Group, RGBAFormat } from 'three';
|
||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
|
||||
import { MotionEngine } from '../../lib/MotionEngine';
|
||||
|
||||
var Game4 = function(context, gltf, w, h){
|
||||
this.game = new Group();
|
||||
const aq = new MotionEngine();
|
||||
const pr = [];
|
||||
let d = .51, c = w * h / 2, tc = w * h, m0=1, r0=.2;
|
||||
let lastClicked;
|
||||
|
||||
function setMaterial(m, v){
|
||||
if (v){
|
||||
m.metalness = .5;
|
||||
m.roughness = .383;
|
||||
}else{
|
||||
m.metalness = m0;
|
||||
m.roughness = r0;
|
||||
m.transparent = true;
|
||||
m.format = RGBAFormat;
|
||||
}
|
||||
}
|
||||
|
||||
new GLTFLoader().load(gltf, gltf=>{
|
||||
for (let i = 0; i<c; i++){
|
||||
let o = gltf.scene.getObjectByName('c'+(i+1));
|
||||
let ref = [];
|
||||
for (let j = 0; j<2; j++){
|
||||
let position;
|
||||
do {
|
||||
position = Math.floor(Math.random() * tc);
|
||||
}while (pr[position]);
|
||||
ref[j] = o.clone();
|
||||
ref[j].material = o.material.clone();
|
||||
setMaterial(ref[j].material, 0);
|
||||
pr[position] = ref[j];
|
||||
}
|
||||
ref[0].$ref = ref[1];
|
||||
ref[1].$ref = ref[0];
|
||||
}
|
||||
pr.forEach((c, i)=>{
|
||||
c.position.set((i % w)*d , (~~(i / w))*d);
|
||||
c.rotation.set(0, Math.PI, 0);
|
||||
this.game.add(c);
|
||||
context.clickable.add(c, clickFn);
|
||||
})
|
||||
|
||||
this.game.children[0].onBeforeRender = ()=>{
|
||||
this.update();
|
||||
}
|
||||
});
|
||||
|
||||
var check = ()=>{
|
||||
if (!this.game.children.length) return false;
|
||||
return pr.filter(c=>c.$active === false).length == tc;
|
||||
}
|
||||
|
||||
let clickFn = (i)=>{
|
||||
let clicked = i.object;
|
||||
if (this.done && clicked){
|
||||
aq.add({
|
||||
o: clicked,
|
||||
a: {rotation:{y: Math.PI}},
|
||||
t: 1,
|
||||
m: 'offset'
|
||||
});
|
||||
}
|
||||
if (!clicked || clicked.$active === false || aq.isActive(clicked)) return;
|
||||
setMaterial(clicked.material, 1);
|
||||
let f;
|
||||
if (lastClicked && lastClicked.$ref == clicked){
|
||||
clicked.$active = lastClicked.$active = false;
|
||||
[clicked, lastClicked].forEach(c => {
|
||||
aq.add({
|
||||
o: c,
|
||||
a: {material:{opacity:0}},
|
||||
t: 1,
|
||||
d:1
|
||||
});
|
||||
});
|
||||
lastClicked = null;
|
||||
}else if(!lastClicked){
|
||||
lastClicked = clicked;
|
||||
}else{
|
||||
f = ()=>{
|
||||
setTimeout(()=>{
|
||||
[clicked, lastClicked].filter(c=>c).forEach(c=>{
|
||||
aq.add({
|
||||
o: c,
|
||||
a: {rotation:{y: Math.PI}, material:{metalness:m0, roughness:r0}},
|
||||
t: 1
|
||||
});
|
||||
});
|
||||
lastClicked = null;
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
aq.add({
|
||||
o: clicked,
|
||||
a: {rotation:{y: 0}},
|
||||
t: .5,
|
||||
f
|
||||
});
|
||||
}
|
||||
|
||||
this.update = ()=>{
|
||||
aq.update();
|
||||
if (!this.done && check()){
|
||||
this.done = true;
|
||||
this.game.children.forEach((c, i)=>{
|
||||
aq.add({
|
||||
o: c,
|
||||
a: {material:{opacity:1}},
|
||||
t: 1,
|
||||
d:1+0.1*i
|
||||
})
|
||||
})
|
||||
this.onfinish && this.onfinish();
|
||||
//context.dashboard.addPoints(10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { Game4 }
|
||||
@@ -0,0 +1,29 @@
|
||||
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.videoPlayer = plane;
|
||||
|
||||
context.clickable.add(plane, ()=>{
|
||||
material.opacity = 0.9
|
||||
if (video.paused){
|
||||
video.play();
|
||||
}else{
|
||||
video.pause();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export {VideoPlayer}
|
||||
@@ -0,0 +1,60 @@
|
||||
<template>
|
||||
<v-card v-if="selected" :title="modelValue.title" class="mx-2" variant="text">
|
||||
<asset-selector @select="assignVideoObject" :type="['Descriptive']">
|
||||
<template v-slot:activator="props">
|
||||
<v-btn v-bind="props" prepend-icon="mdi-panorama-outline" color="success" block>Choose video object</v-btn>
|
||||
</template>
|
||||
</asset-selector>
|
||||
<v-form class="py-4">
|
||||
<v-text-field density="compact" :label="l.name" v-model="modelValue.title"></v-text-field>
|
||||
<v-textarea :label="l.description" v-model="modelValue.description"></v-textarea>
|
||||
<v-text-field density="compact" :label="l.id" v-model="modelValue.id"></v-text-field>
|
||||
</v-form>
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import Utils from '@/lib/utils';
|
||||
|
||||
export default {
|
||||
emits:['target', 'preview'],
|
||||
data(){
|
||||
return {
|
||||
active: false
|
||||
}
|
||||
},
|
||||
mounted(){
|
||||
this.active = true;
|
||||
},
|
||||
props:{
|
||||
//context: Object,
|
||||
modelValue: Object,
|
||||
vd: Object,
|
||||
selected: Boolean,
|
||||
cid:String,
|
||||
visible: Boolean,
|
||||
parent: Object
|
||||
},
|
||||
computed:{
|
||||
showInView(){
|
||||
this.vd.__showInView = this.visible && this.parent.visible;
|
||||
return this.vd.__showInView;
|
||||
}
|
||||
},
|
||||
steps: [['x1', 'y1']],
|
||||
name: 'game-object',
|
||||
modifiers: ['x1', 'y1'],
|
||||
methods:{
|
||||
intersect(v){
|
||||
return Utils.intersectPointRect([this.vd.x1, this.vd.y1], v);
|
||||
},
|
||||
assignGameObject(e){
|
||||
this.modelValue.go = e.id;
|
||||
if (this.modelValue.id == this.modelValue.title){
|
||||
this.modelValue.title = e.name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user