classic puzzle v1
This commit is contained in:
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -20,7 +20,11 @@
|
|||||||
<v-btn icon="mdi-walk" @click="control"></v-btn>
|
<v-btn icon="mdi-walk" @click="control"></v-btn>
|
||||||
</v-navigation-drawer>
|
</v-navigation-drawer>
|
||||||
<div class="container my-3 position-relative game-designer-canvas">
|
<div class="container my-3 position-relative game-designer-canvas">
|
||||||
<div ref="target" @click="targetClick" @pointerdown="targetPointerDown"></div>
|
<div ref="target" @click="targetClick"
|
||||||
|
@mousedown="targetPointer($event, 'start')"
|
||||||
|
@mousemove="targetPointer($event, 'drag')"
|
||||||
|
@mouseup="targetPointer($event, 'end')"
|
||||||
|
@pointerdown="targetPointerDown"></div>
|
||||||
</div>
|
</div>
|
||||||
<!-- <v-toolbar density="compact">
|
<!-- <v-toolbar density="compact">
|
||||||
<v-slide-group show-arrows>
|
<v-slide-group show-arrows>
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
import { Color, Group, EventDispatcher, DoubleSide } from "three"
|
||||||
|
import { centerOrigin } from "@/lib/MeshUtils";
|
||||||
|
|
||||||
|
class ClassicPuzzle extends EventDispatcher {
|
||||||
|
emits = ['finish']
|
||||||
|
constructor(engine, data, gltfName, objPrefix='Plane'){
|
||||||
|
super();
|
||||||
|
const container = new Group();
|
||||||
|
const that = this;
|
||||||
|
return new Promise(async (resolve, reject)=>{
|
||||||
|
let gltf = await engine.load('puzzle-5x4/puzzle-5x4.gltf', '/static/meshes/');
|
||||||
|
let dragZone = gltf.scene.getObjectByName('DragZone');
|
||||||
|
dragZone.material.side = DoubleSide;
|
||||||
|
let eventsFn= {
|
||||||
|
start(){},
|
||||||
|
drag(){},
|
||||||
|
end(e){
|
||||||
|
if (Math.abs(e.o.position.x)<.1 && Math.abs(e.o.position.y)<.1){
|
||||||
|
e.o.position.set(0,0,0);
|
||||||
|
engine.draggable.remove(e.o);
|
||||||
|
e.o.material = doneMaterial;
|
||||||
|
done++;
|
||||||
|
if (done == pCount){
|
||||||
|
doneMaterial.emissiveIntensity = .5;
|
||||||
|
engine.motionQueue.add({
|
||||||
|
o: doneMaterial,
|
||||||
|
t:1.5,
|
||||||
|
d:1,
|
||||||
|
a:{ emissiveIntensity:0 },
|
||||||
|
f:()=>{
|
||||||
|
that.dispatchEvent({type:'finish'})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let pCount = 0;
|
||||||
|
dragZone.visible = false;
|
||||||
|
gltf.scene.children.forEach((o, i)=>{
|
||||||
|
if (o.name.startsWith(objPrefix)){
|
||||||
|
let pp = o.clone();
|
||||||
|
container.add(pp);
|
||||||
|
pp.position.set(2*Math.random()-1, 2*Math.random() - 1, 0.01*(i+1));
|
||||||
|
engine.draggable.add(pp, dragZone, eventsFn);
|
||||||
|
pCount++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let defaultMaterial = container.children[0].material;
|
||||||
|
defaultMaterial.emissiveIntensity=.05
|
||||||
|
let doneMaterial = defaultMaterial.clone();
|
||||||
|
doneMaterial.emissive = new Color(10,114,10);
|
||||||
|
defaultMaterial.emissive = new Color(114,10,10);
|
||||||
|
engine.motionQueue.add(
|
||||||
|
{
|
||||||
|
o: defaultMaterial,
|
||||||
|
r: true,
|
||||||
|
t:1.5,
|
||||||
|
d:1,
|
||||||
|
rd:true,
|
||||||
|
a:{emissiveIntensity:function(k){return .05*Math.sin(k*3.14);}}
|
||||||
|
});
|
||||||
|
let done0 = container.children[Math.floor(Math.random() * container.children.length)];
|
||||||
|
let done = 1;
|
||||||
|
done0.material = doneMaterial;
|
||||||
|
done0.position.set(0,0,0);
|
||||||
|
engine.draggable.remove(done0)
|
||||||
|
container.add(dragZone);
|
||||||
|
this.object = centerOrigin(container);
|
||||||
|
resolve(this);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { ClassicPuzzle }
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
<template>
|
||||||
|
<div v-if="modelValue.go">
|
||||||
|
<v-number-input density="compact" label="Width" v-model="modelValue.w"></v-number-input>
|
||||||
|
<v-number-input density="compact" label="Height" v-model="modelValue.h"></v-number-input>
|
||||||
|
<v-img :src="`/asset/thumb/${modelValue.go}.webp`" />
|
||||||
|
<div class="text-caption text-center">{{ modelValue.title }}</div>
|
||||||
|
</div>
|
||||||
|
<asset-selector @select="assignTexture" :type="['Texture']">
|
||||||
|
<template v-slot:activator="props">
|
||||||
|
<v-btn v-bind="props" prepend-icon="mdi-video-box" color="deep-orange-darken-4" block>Choose image object</v-btn>
|
||||||
|
</template>
|
||||||
|
</asset-selector>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data(){
|
||||||
|
return {
|
||||||
|
active: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted(){
|
||||||
|
this.active = true;
|
||||||
|
},
|
||||||
|
props:{
|
||||||
|
modelValue: Object
|
||||||
|
},
|
||||||
|
methods:{
|
||||||
|
assignTexture(e){
|
||||||
|
this.modelValue.go = e.id;
|
||||||
|
this.modelValue.title = e.name
|
||||||
|
// this.modelValue.w = 2;
|
||||||
|
// this.modelValue.h = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -9,6 +9,7 @@ import { PuzzleGame1 } from "./PuzzleGame1";
|
|||||||
import { PuzzleGame2 } from "./PuzzleGame2";
|
import { PuzzleGame2 } from "./PuzzleGame2";
|
||||||
// import { Game3 } from "./games/Game3";
|
// import { Game3 } from "./games/Game3";
|
||||||
import { PuzzleGame4 } from "./PuzzleGame4";
|
import { PuzzleGame4 } from "./PuzzleGame4";
|
||||||
|
import { ClassicPuzzle } from "./ClassicPuzzle";
|
||||||
// import { Game5 } from "./games/Game5";
|
// import { Game5 } from "./games/Game5";
|
||||||
// import { Game6 } from "./games/Game6";
|
// import { Game6 } from "./games/Game6";
|
||||||
import { MazeQuizGame } from "./MazeQuizGame/MazeQuizGame";
|
import { MazeQuizGame } from "./MazeQuizGame/MazeQuizGame";
|
||||||
@@ -18,7 +19,7 @@ import { GameEngine } from "@/lib/GameEngine";
|
|||||||
|
|
||||||
const InteractiveObjectsImports = {
|
const InteractiveObjectsImports = {
|
||||||
GenericObject, CharacterObject, TextObject, ImageObject, VideoPlayer, Particles,
|
GenericObject, CharacterObject, TextObject, ImageObject, VideoPlayer, Particles,
|
||||||
PuzzleGame1, PuzzleGame2, PuzzleGame4, MazeQuizGame
|
PuzzleGame1, PuzzleGame2, PuzzleGame4, MazeQuizGame, ClassicPuzzle
|
||||||
};
|
};
|
||||||
|
|
||||||
class InteractiveObject extends EventDispatcher{
|
class InteractiveObject extends EventDispatcher{
|
||||||
@@ -66,6 +67,7 @@ class InteractiveObject extends EventDispatcher{
|
|||||||
case 'PuzzleGame1':
|
case 'PuzzleGame1':
|
||||||
case 'PuzzleGame2':
|
case 'PuzzleGame2':
|
||||||
case 'MazeQuizGame':
|
case 'MazeQuizGame':
|
||||||
|
case 'ClassicPuzzle':
|
||||||
case 'Particles':
|
case 'Particles':
|
||||||
this.io = await new InteractiveObjectsImports[obj.type](gameEngine, obj);
|
this.io = await new InteractiveObjectsImports[obj.type](gameEngine, obj);
|
||||||
this.source = this.io.source || this.io;
|
this.source = this.io.source || this.io;
|
||||||
@@ -131,6 +133,8 @@ const InteractiveObjectTypes = [
|
|||||||
id: 'PuzzleGame2', name: 'Puzzle Game 2'
|
id: 'PuzzleGame2', name: 'Puzzle Game 2'
|
||||||
},{
|
},{
|
||||||
id: 'MazeQuizGame', name: 'Maze Quiz Game'
|
id: 'MazeQuizGame', name: 'Maze Quiz Game'
|
||||||
|
},{
|
||||||
|
id: 'ClassicPuzzle', name: 'Classic Puzzle Game'
|
||||||
},{
|
},{
|
||||||
id: 'VideoPlayer', name: 'Video Player'
|
id: 'VideoPlayer', name: 'Video Player'
|
||||||
},{
|
},{
|
||||||
|
|||||||
@@ -43,12 +43,12 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import SvgIcon from './SvgIcon.vue';
|
import SvgIcon from './SvgIcon.vue';
|
||||||
import Utils from '@/lib/Utils';
|
|
||||||
|
|
||||||
import VideoPlayer from '../InteractiveObjects/VideoPlayer.vue';
|
import VideoPlayer from '../InteractiveObjects/VideoPlayer.vue';
|
||||||
import PuzzleGame1 from '../InteractiveObjects/PuzzleGame1.vue';
|
import PuzzleGame1 from '../InteractiveObjects/PuzzleGame1.vue';
|
||||||
import PuzzleGame2 from '../InteractiveObjects/PuzzleGame2.vue';
|
import PuzzleGame2 from '../InteractiveObjects/PuzzleGame2.vue';
|
||||||
import MazeQuizGame from '../InteractiveObjects/MazeQuizGame/MazeQuizGame.vue';
|
import MazeQuizGame from '../InteractiveObjects/MazeQuizGame/MazeQuizGame.vue';
|
||||||
|
import ClassicPuzzle from '../InteractiveObjects/ClassicPuzzle.vue';
|
||||||
import Particles from '../InteractiveObjects/Particles.vue';
|
import Particles from '../InteractiveObjects/Particles.vue';
|
||||||
import GenericObject from '../InteractiveObjects/GenericObject.vue';
|
import GenericObject from '../InteractiveObjects/GenericObject.vue';
|
||||||
import CharacterObject from '../InteractiveObjects/CharacterObject.vue';
|
import CharacterObject from '../InteractiveObjects/CharacterObject.vue';
|
||||||
@@ -56,7 +56,10 @@ import OffsetLine from './OffsetLine.vue';
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
emits:['target', 'preview'],
|
emits:['target', 'preview'],
|
||||||
components: { SvgIcon, OffsetLine, GenericObject, CharacterObject, VideoPlayer, PuzzleGame1, PuzzleGame2, MazeQuizGame, Particles, },
|
components: {
|
||||||
|
SvgIcon, OffsetLine, GenericObject, CharacterObject, VideoPlayer,
|
||||||
|
PuzzleGame1, PuzzleGame2, MazeQuizGame, Particles, ClassicPuzzle
|
||||||
|
},
|
||||||
data(){
|
data(){
|
||||||
return {
|
return {
|
||||||
active: false
|
active: false
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import { Raycaster, Vector3 } from "three"
|
||||||
|
|
||||||
|
class Draggable{
|
||||||
|
constructor(defaultDistance){
|
||||||
|
const objects = [];
|
||||||
|
const raycaster = new Raycaster();
|
||||||
|
let v = new Vector3;
|
||||||
|
let dragging = null;
|
||||||
|
this.add = function(object, dragZone, fn, distance){
|
||||||
|
objects.push(object);
|
||||||
|
object._draggable = {fn, dragZone, distance: distance || defaultDistance}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.remove = function(object){
|
||||||
|
delete object._draggable;
|
||||||
|
objects.splice(objects.indexOf(object), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.update = function(pointer, camera, action){
|
||||||
|
raycaster.setFromCamera(pointer, camera);
|
||||||
|
if (action == 'start'){
|
||||||
|
let forExecute = [];
|
||||||
|
objects.forEach(o=>{
|
||||||
|
o.getWorldPosition(v);
|
||||||
|
if (camera.position.distanceTo(v) <= o._draggable.distance && o.visible){
|
||||||
|
const intersects = raycaster.intersectObject(o);
|
||||||
|
if (intersects[0]) forExecute.push({o, i:intersects[0]})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (forExecute[0]) {
|
||||||
|
let s = forExecute.sort((a,b)=>a.i.distance-b.i.distance)[0];
|
||||||
|
s.o._draggable.fn.start && s.o._draggable.fn.start(s.i);
|
||||||
|
dragging = s;
|
||||||
|
dragging.zone = raycaster.intersectObject(s.o._draggable.dragZone)[0];
|
||||||
|
}
|
||||||
|
}else if (action == 'end' && dragging){
|
||||||
|
dragging.o._draggable.fn.end && dragging.o._draggable.fn.end(dragging);
|
||||||
|
dragging = null;
|
||||||
|
}else if(action == 'drag' && dragging){
|
||||||
|
const intersect = raycaster.intersectObject(dragging.o._draggable.dragZone)[0];
|
||||||
|
if (intersect?.uv && dragging.zone?.uv){
|
||||||
|
dragging.o.position.x += -4*(dragging.zone.uv.x - intersect.uv.x);
|
||||||
|
dragging.o.position.y += 4*(dragging.zone.uv.y - intersect.uv.y);
|
||||||
|
dragging.o._draggable.fn.drag && dragging.o._draggable.fn.drag(dragging);
|
||||||
|
dragging.zone = intersect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Draggable }
|
||||||
@@ -15,6 +15,7 @@ import { Physics } from './Physics.js';
|
|||||||
import { Clickable } from './Clickable.js';
|
import { Clickable } from './Clickable.js';
|
||||||
import { DashBoard } from './Dashboard.js';
|
import { DashBoard } from './Dashboard.js';
|
||||||
import { MotionEngine } from './MotionEngine.js';
|
import { MotionEngine } from './MotionEngine.js';
|
||||||
|
import { Draggable } from './Draggable.js';
|
||||||
|
|
||||||
THREE.Cache.enabled = true
|
THREE.Cache.enabled = true
|
||||||
|
|
||||||
@@ -209,6 +210,7 @@ class GameEngine extends THREE.EventDispatcher{
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.clickable = new Clickable(20);
|
this.clickable = new Clickable(20);
|
||||||
|
this.draggable = new Draggable(20);
|
||||||
}
|
}
|
||||||
|
|
||||||
initXrControllers() {
|
initXrControllers() {
|
||||||
@@ -485,6 +487,11 @@ class GameEngine extends THREE.EventDispatcher{
|
|||||||
this.hero?.characterControls?.idleReset();
|
this.hero?.characterControls?.idleReset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onPointer(mouseEvent, domElement, type){
|
||||||
|
let mouse = this.getMouseVector(mouseEvent, domElement);
|
||||||
|
this.draggable?.update(mouse, this.camera, type);
|
||||||
|
}
|
||||||
|
|
||||||
setCamera(camera) {
|
setCamera(camera) {
|
||||||
//camera.updateProjectionMatrix();
|
//camera.updateProjectionMatrix();
|
||||||
this.camera = camera;
|
this.camera = camera;
|
||||||
|
|||||||
@@ -123,6 +123,8 @@ export default {
|
|||||||
await this.expandScenarioData(scene);
|
await this.expandScenarioData(scene);
|
||||||
gameEngine.dashboard?.loading(0.1);
|
gameEngine.dashboard?.loading(0.1);
|
||||||
|
|
||||||
|
gameEngine.orbitControls.enableRotate = this.env == 'GameDesigner'
|
||||||
|
|
||||||
//this is needed cause when mounted canvas has different size
|
//this is needed cause when mounted canvas has different size
|
||||||
this.resize();
|
this.resize();
|
||||||
target.objects = target.objects || {};
|
target.objects = target.objects || {};
|
||||||
@@ -212,6 +214,7 @@ export default {
|
|||||||
gameEngine.activeObjects.add(intro.object);
|
gameEngine.activeObjects.add(intro.object);
|
||||||
intro.video.addEventListener('pause',()=>{
|
intro.video.addEventListener('pause',()=>{
|
||||||
intro.object.removeFromParent();
|
intro.object.removeFromParent();
|
||||||
|
gameEngine.clickable.remove(intro.object); //TODO!!!!
|
||||||
gameEngine.activeObjects.visible = true;
|
gameEngine.activeObjects.visible = true;
|
||||||
});
|
});
|
||||||
intro.video.play();
|
intro.video.play();
|
||||||
@@ -244,6 +247,10 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
targetPointer(e, t){
|
||||||
|
gameEngine.onPointer(e, this.$refs.target, t);
|
||||||
|
},
|
||||||
|
|
||||||
setObjectAttributes(l, data, object, source, autoScaleFactor = 1){
|
setObjectAttributes(l, data, object, source, autoScaleFactor = 1){
|
||||||
if (l[data.id]){
|
if (l[data.id]){
|
||||||
['position', 'scale', 'rotation'].forEach(p=>{
|
['position', 'scale', 'rotation'].forEach(p=>{
|
||||||
|
|||||||
Reference in New Issue
Block a user