scene switcher feature
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import { Group, EventDispatcher, MeshStandardMaterial, Mesh, SphereGeometry } from "three";
|
import { Group, MeshStandardMaterial, Mesh, SphereGeometry, Vector3 } from "three";
|
||||||
|
import { EventManager } from '@/lib/EventManager';
|
||||||
|
|
||||||
import { GenericObject } from "./GenenricObject";
|
import { GenericObject } from "./GenenricObject";
|
||||||
import { TextObject } from "./TextObject";
|
import { TextObject } from "./TextObject";
|
||||||
@@ -15,16 +16,17 @@ import { ClassicPuzzle } from "./ClassicPuzzle";
|
|||||||
// import { Game6 } from "./games/Game6";
|
// import { Game6 } from "./games/Game6";
|
||||||
import { MazeQuizGame } from "./MazeQuizGame/MazeQuizGame";
|
import { MazeQuizGame } from "./MazeQuizGame/MazeQuizGame";
|
||||||
import { Particles } from "./Particles";
|
import { Particles } from "./Particles";
|
||||||
import { assignMaterial, assignParams, wrapInGroup, getBoundingBoxMaxLength } from "@/lib/MeshUtils";
|
import { SceneSwitcher } from "./SceneSwitcher";
|
||||||
|
import { assignParams, wrapInGroup, getBoundingBoxMaxLength } from "@/lib/MeshUtils";
|
||||||
import { GameEngine } from "@/lib/GameEngine";
|
import { GameEngine } from "@/lib/GameEngine";
|
||||||
|
|
||||||
const InteractiveObjectsImports = {
|
const InteractiveObjectsImports = {
|
||||||
GenericObject, CharacterObject, TextObject, ImageObject, GltfObject, VideoPlayer, Particles,
|
GenericObject, CharacterObject, TextObject, ImageObject, GltfObject, VideoPlayer, Particles, SceneSwitcher,
|
||||||
PuzzleGame1, PuzzleGame2, PuzzleGame4, MazeQuizGame, ClassicPuzzle
|
PuzzleGame1, PuzzleGame2, PuzzleGame4, MazeQuizGame, ClassicPuzzle
|
||||||
};
|
};
|
||||||
|
|
||||||
class InteractiveObject extends EventDispatcher{
|
class InteractiveObject extends EventManager{
|
||||||
constructor(gameEngine, obj) {
|
constructor(engine, obj) {
|
||||||
super();
|
super();
|
||||||
this.name = obj.name;
|
this.name = obj.name;
|
||||||
return new Promise(async (resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
@@ -32,7 +34,7 @@ class InteractiveObject extends EventDispatcher{
|
|||||||
case 'Group':
|
case 'Group':
|
||||||
this.object = new Group();
|
this.object = new Group();
|
||||||
for (let g of obj.group){
|
for (let g of obj.group){
|
||||||
let gameMesh = await new InteractiveObject(gameEngine, g);
|
let gameMesh = await new InteractiveObject(engine, g);
|
||||||
this.object.add(gameMesh.object);
|
this.object.add(gameMesh.object);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -47,38 +49,72 @@ class InteractiveObject extends EventDispatcher{
|
|||||||
case 'MazeQuizGame':
|
case 'MazeQuizGame':
|
||||||
case 'ClassicPuzzle':
|
case 'ClassicPuzzle':
|
||||||
case 'Particles':
|
case 'Particles':
|
||||||
this.io = await new InteractiveObjectsImports[obj.type](gameEngine, obj);
|
case 'SceneSwitcher':
|
||||||
|
this.io = await new InteractiveObjectsImports[obj.type](engine, obj);
|
||||||
this.source = this.io.source || this.io;
|
this.source = this.io.source || this.io;
|
||||||
this.object = this.io.object;
|
this.object = this.io.object;
|
||||||
this.emits = this.io.emits;
|
this.emits = this.io.emits;
|
||||||
this.io.emits?.forEach(event=>{
|
// this.io.emits?.forEach(event=>{
|
||||||
this.io.addEventListener?.(event, this.dispatchEvent.bind(this))
|
// this.io.addEventListener?.(event, this.dispatchEvent.bind(this))
|
||||||
})
|
// })
|
||||||
|
this.io.forwardEvents?.(this);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (obj.shouldBeLocked){
|
if (obj.shouldBeLocked){
|
||||||
this.object = wrapInGroup(this.object)
|
this.object = wrapInGroup(this.object)
|
||||||
this.locker = new Locker(gameEngine, this.object);
|
this.activator = new (obj.activationType == 'unlock' ? LockActivator : VisibilityActivator)(engine, this.object);
|
||||||
this.locker.lock();
|
this.activator.deactivate();
|
||||||
}
|
}
|
||||||
assignParams(this.object, obj);
|
assignParams(this.object, obj);
|
||||||
if (obj.motion){
|
if (obj.motion){
|
||||||
gameEngine.motionQueue.add({
|
engine.motionQueue.add({
|
||||||
o: this.object, ...obj.motion
|
o: this.object, ...obj.motion
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (obj.distance) {
|
||||||
|
const o = this.object;
|
||||||
|
let dstm = obj.distance;
|
||||||
|
let v = new Vector3();
|
||||||
|
o.visible = false;
|
||||||
|
engine.addEventListener('beforeRender', function () {
|
||||||
|
o.getWorldPosition(v);
|
||||||
|
var dst = engine.camera.position.distanceTo(v);
|
||||||
|
if (dst <= dstm && !o.visible) {
|
||||||
|
o.visible = true;
|
||||||
|
}else if (dst > dstm && o.visible){
|
||||||
|
o.visible = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
resolve(this);
|
resolve(this);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Locker{
|
class VisibilityActivator{
|
||||||
|
constructor(engine, group){
|
||||||
|
this.deactivate = function(){
|
||||||
|
group.visible = false;
|
||||||
|
group.__active = false;
|
||||||
|
}
|
||||||
|
this.activate = function(){
|
||||||
|
group.visible = true;
|
||||||
|
group.__active = true;
|
||||||
|
}
|
||||||
|
this.isActive = function(){
|
||||||
|
return group.__active;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LockActivator{
|
||||||
static materialLocked = new MeshStandardMaterial({
|
static materialLocked = new MeshStandardMaterial({
|
||||||
transparent: true, opacity:1, color: 0xaaaaaa
|
transparent: true, opacity:1, color: 0xaaaaaa
|
||||||
})
|
})
|
||||||
constructor(engine, group){
|
constructor(engine, group){
|
||||||
const bckGeometry = new SphereGeometry(getBoundingBoxMaxLength(group.userData.bbox)/2,8,8)
|
const bckGeometry = new SphereGeometry(getBoundingBoxMaxLength(group.userData.bbox)/2,8,8)
|
||||||
const bckMesh = new Mesh(bckGeometry, Locker.materialLocked);
|
const bckMesh = new Mesh(bckGeometry, LockActivator.materialLocked);
|
||||||
bckMesh.visible = false;
|
bckMesh.visible = false;
|
||||||
group.add(bckMesh)
|
group.add(bckMesh)
|
||||||
function animate(){
|
function animate(){
|
||||||
@@ -91,24 +127,29 @@ class Locker{
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
this.object = bckMesh;
|
this.object = bckMesh;
|
||||||
this.lock = function(){
|
this.deactivate = function(){
|
||||||
bckMesh.visible = true;
|
bckMesh.visible = true;
|
||||||
//bckMesh.material.needsUpdate = true;
|
//bckMesh.material.needsUpdate = true;
|
||||||
engine.motionQueue.clear(bckMesh);
|
engine.motionQueue.clear(bckMesh);
|
||||||
group.__locked = true;
|
group.__active = false;
|
||||||
animate();
|
animate();
|
||||||
}
|
}
|
||||||
this.unlock = function(){
|
this.activate = function(){
|
||||||
bckMesh.visible = false;
|
bckMesh.visible = false;
|
||||||
engine.motionQueue.clear(bckMesh);
|
engine.motionQueue.clear(bckMesh);
|
||||||
group.__locked = false;
|
group.__active = true;
|
||||||
|
}
|
||||||
|
this.isActive = function(){
|
||||||
|
return group.__active;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GameEngine.loadTexture('locked.webp', '/static/textures/', null, [Locker.materialLocked, 'alphaMap'])
|
GameEngine.loadTexture('locked.webp', '/static/textures/', null, [LockActivator.materialLocked, 'alphaMap'])
|
||||||
|
|
||||||
const InteractiveObjectTypes = [
|
const InteractiveObjectTypes = [
|
||||||
{
|
{
|
||||||
|
id: 'GenericObject', name: 'Generic Game Object'
|
||||||
|
},{
|
||||||
id: 'CharacterObject', name: 'Character'
|
id: 'CharacterObject', name: 'Character'
|
||||||
}, {
|
}, {
|
||||||
id: 'PuzzleGame1', name: 'Puzzle Game 1'
|
id: 'PuzzleGame1', name: 'Puzzle Game 1'
|
||||||
@@ -122,6 +163,8 @@ const InteractiveObjectTypes = [
|
|||||||
id: 'VideoPlayer', name: 'Video Player'
|
id: 'VideoPlayer', name: 'Video Player'
|
||||||
},{
|
},{
|
||||||
id: 'Particles', name: 'Particles'
|
id: 'Particles', name: 'Particles'
|
||||||
|
},{
|
||||||
|
id: 'SceneSwitcher', name: 'Scene Switcher'
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -126,6 +126,7 @@ class MazeObject {
|
|||||||
go.object.scale.multiplyScalar(wallSize)
|
go.object.scale.multiplyScalar(wallSize)
|
||||||
go.object.position.multiplyScalar(wallSize)
|
go.object.position.multiplyScalar(wallSize)
|
||||||
go.object.applyMatrix4(def.matrix);
|
go.object.applyMatrix4(def.matrix);
|
||||||
|
go.forwardEvents?.(params.io);
|
||||||
root.add(go.object);
|
root.add(go.object);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { MazeObject } from "./MazeObject";
|
import { MazeObject } from "./MazeObject";
|
||||||
import Utils from "@/lib/Utils";
|
import Utils from "@/lib/Utils";
|
||||||
import { EventDispatcher } from "three";
|
import { EventManager } from '@/lib/EventManager';
|
||||||
|
|
||||||
const params = {
|
const params = {
|
||||||
scale: 3,
|
scale: 3,
|
||||||
@@ -17,7 +17,7 @@ const imgParams = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const textParams = {
|
const textParams = {
|
||||||
type: 'TextObject', width:0.44,
|
type: 'TextObject', maxWidth:0.44,
|
||||||
fontPath:'/static/fonts/Montserrat-Regular.ttf',
|
fontPath:'/static/fonts/Montserrat-Regular.ttf',
|
||||||
fontSize:0.025, distance: params.wallSize*2
|
fontSize:0.025, distance: params.wallSize*2
|
||||||
}
|
}
|
||||||
@@ -37,12 +37,14 @@ const defaults = {
|
|||||||
|
|
||||||
const tl = 4;
|
const tl = 4;
|
||||||
|
|
||||||
class MazeQuizGame extends EventDispatcher {
|
class MazeQuizGame extends EventManager {
|
||||||
emits = ['finish']
|
emits = ['finish', 'sceneSwitch']
|
||||||
constructor(engine, data) {
|
constructor(engine, data) {
|
||||||
super();
|
super();
|
||||||
|
this.data = data;
|
||||||
data.noPhysics = true;
|
data.noPhysics = true;
|
||||||
params.mazeFile = data.style || 'quiz-s2.gltf';
|
params.mazeFile = data.style || 'quiz-s2.gltf';
|
||||||
|
params.io = this;
|
||||||
return new Promise(async (resolve, reject)=>{
|
return new Promise(async (resolve, reject)=>{
|
||||||
let questions = data.shuffle ? Utils.shuffleArray(data.questions) : data.questions;
|
let questions = data.shuffle ? Utils.shuffleArray(data.questions) : data.questions;
|
||||||
let def = this.generate(questions);
|
let def = this.generate(questions);
|
||||||
@@ -101,11 +103,16 @@ class MazeQuizGame extends EventDispatcher {
|
|||||||
len,
|
len,
|
||||||
userData: { finish: true },
|
userData: { finish: true },
|
||||||
objects:[
|
objects:[
|
||||||
|
// {
|
||||||
|
// type: 'GltfObject',
|
||||||
|
// position:[0,.22,len + .52], scale: [0.33, 0.33, 0.33], rotation: [0, Math.PI/4, 0],
|
||||||
|
// value: 'trophy.glb', path: imgParams.path, distance: params.wallSize*2,
|
||||||
|
// motion: { a:{rotation: { y: k=>k*Math.PI*2 }}, r: true, t: 4 }
|
||||||
|
// }
|
||||||
{
|
{
|
||||||
type: 'GltfObject',
|
type: 'SceneSwitcher', switchScene: this.data.switchScene, switchType: this.data.switchType,
|
||||||
position:[0,.22,len + .52], scale: [0.33, 0.33, 0.33], rotation: [0, Math.PI/4, 0],
|
position:[0,.22,len + .52], scale: [0.33, 0.33, 0.33],
|
||||||
value: 'trophy.glb', path: imgParams.path, distance: params.wallSize*2,
|
distance: params.wallSize*2
|
||||||
motion: { a:{rotation: { y: k=>k*Math.PI*2 }}, r: true, t: 4 }
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
@@ -116,7 +123,7 @@ class MazeQuizGame extends EventDispatcher {
|
|||||||
len, userData: { question, qid },
|
len, userData: { question, qid },
|
||||||
objects:[
|
objects:[
|
||||||
{
|
{
|
||||||
...textParams, text: question.q, fontSize:0.033, width:0.55, position:[0,.55,len + .96], rotation:[0,Math.PI, 0]
|
...textParams, text: question.q, fontSize:0.033, maxWidth:0.55, position:[0,.55,len + .96], rotation:[0,Math.PI, 0]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -149,7 +156,7 @@ class MazeQuizGame extends EventDispatcher {
|
|||||||
len: 3,
|
len: 3,
|
||||||
objects:[
|
objects:[
|
||||||
{
|
{
|
||||||
...textParams, color:0xc71414, text: question.h, fontSize:0.033, width:0.66, position:[0,.44,3+.96], rotation:[0,Math.PI, 0]
|
...textParams, color:0xc71414, text: question.h, fontSize:0.033, maxWidth:0.66, position:[0,.44,3+.96], rotation:[0,Math.PI, 0]
|
||||||
},{
|
},{
|
||||||
...imgParams, value:'x.webp', position:[0,.33,3+.96], rotation:[0,Math.PI, 0]
|
...imgParams, value:'x.webp', position:[0,.33,3+.96], rotation:[0,Math.PI, 0]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,10 +39,13 @@
|
|||||||
<v-checkbox v-model="modelValue.shuffle" hide-details label="Shuffle questions"></v-checkbox>
|
<v-checkbox v-model="modelValue.shuffle" hide-details label="Shuffle questions"></v-checkbox>
|
||||||
<v-number-input density="compact" label="Correct answer points" v-model="modelValue.questionPoints"></v-number-input>
|
<v-number-input density="compact" label="Correct answer points" v-model="modelValue.questionPoints"></v-number-input>
|
||||||
<v-number-input density="compact" label="Wrong answer penalty points" v-model="modelValue.questionPenalty"></v-number-input>
|
<v-number-input density="compact" label="Wrong answer penalty points" v-model="modelValue.questionPenalty"></v-number-input>
|
||||||
<v-select v-model="modelValue.style" :items="styles" density="compact" label="VIsual style"></v-select>
|
<v-select v-model="modelValue.style" :items="styles" density="compact" label="Visual style"></v-select>
|
||||||
|
<SceneSwitcher v-model="mv"></SceneSwitcher>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import SceneSwitcher from '../SceneSwitcher.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props:['modelValue'],
|
props:['modelValue'],
|
||||||
data(){
|
data(){
|
||||||
@@ -61,6 +64,11 @@ export default {
|
|||||||
this.modelValue.questionPenalty ??= 0;
|
this.modelValue.questionPenalty ??= 0;
|
||||||
this.modelValue.exclude = true;
|
this.modelValue.exclude = true;
|
||||||
},
|
},
|
||||||
|
computed:{
|
||||||
|
mv(){
|
||||||
|
return this.modelValue;
|
||||||
|
}
|
||||||
|
},
|
||||||
methods:{
|
methods:{
|
||||||
addQuestion(){
|
addQuestion(){
|
||||||
this.modelValue.questions.push({
|
this.modelValue.questions.push({
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import { getBoundingBox, getBoundingBoxCenterPoint, getBoundingBoxMaxLength, centerOrigin } from "@/lib/MeshUtils";
|
||||||
|
import { SphereGeometry, Mesh, MeshStandardMaterial, BackSide, Group } from "three";
|
||||||
|
import { EventManager } from '@/lib/EventManager';
|
||||||
|
|
||||||
|
class SceneSwitcher extends EventManager{
|
||||||
|
emits = ['sceneSwitch']
|
||||||
|
constructor(engine, data){
|
||||||
|
super();
|
||||||
|
return new Promise(async(resolve, reject)=>{
|
||||||
|
this.source = this;
|
||||||
|
this.object = new Group()
|
||||||
|
if (data.switchType == 'award'){
|
||||||
|
let gltf = await engine.load('trophy.glb', '/static/meshes/scene-switcher/');
|
||||||
|
this.object.add(gltf.scene);
|
||||||
|
engine.motionQueue.add({
|
||||||
|
o: gltf.scene,
|
||||||
|
a:{rotation: { y: k=>k*Math.PI*2 }}, r: true, t: 4
|
||||||
|
})
|
||||||
|
}else if(data.switchType == 'sphere'){
|
||||||
|
let geo = new SphereGeometry(1);
|
||||||
|
let material = new MeshStandardMaterial({
|
||||||
|
map: await engine.loadTexture(data.$go_env.asset.name)
|
||||||
|
})
|
||||||
|
let sphere = new Mesh(geo, material);
|
||||||
|
sphere.position.y = 0.5;
|
||||||
|
this.object.add(sphere);
|
||||||
|
}else{
|
||||||
|
//sensor, TODO!!!, to be implemented
|
||||||
|
}
|
||||||
|
engine.clickable.add(this.object, async e=>{
|
||||||
|
this.dispatchEvent({type:'sceneSwitch', scene: data.switchScene});
|
||||||
|
})
|
||||||
|
resolve(this);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { SceneSwitcher }
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<v-select label="Switch to scene" v-model="modelValue.switchScene" density="compact"
|
||||||
|
:items="scenes"></v-select>
|
||||||
|
<v-select label="Switch type" v-model="modelValue.switchType" density="compact"
|
||||||
|
:items="switchTypes"></v-select>
|
||||||
|
<!-- <div class="text-caption text-center">{{ modelValue.title }}</div> -->
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import { computed } from 'vue';
|
||||||
|
import OffsetLine from '../SceneDesigner/OffsetLine.vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components:{ OffsetLine },
|
||||||
|
data(){
|
||||||
|
return {
|
||||||
|
active: false,
|
||||||
|
switchTypes: [
|
||||||
|
{ title: 'Award', value: 'award' },
|
||||||
|
{ title: 'Sphere', value: 'sphere' },
|
||||||
|
{ title: 'Sensor', value: 'sensor' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted(){
|
||||||
|
this.active = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
props:{
|
||||||
|
modelValue: Object
|
||||||
|
},
|
||||||
|
computed:{
|
||||||
|
scenes(){
|
||||||
|
return this.modelValue.__root.scenes.map(s=>({title: s.data.title, value: s.data.id}))
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods:{
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
__transform(data){
|
||||||
|
data.go_env = computed(()=>{
|
||||||
|
if (data.switchType == 'sphere' && data.switchScene){
|
||||||
|
return data.__root.scenes.find(s=>s.data.id == data.switchScene).data.environment;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
@@ -16,12 +16,14 @@
|
|||||||
</image>
|
</image>
|
||||||
</g>
|
</g>
|
||||||
</teleport>
|
</teleport>
|
||||||
|
<teleport to=".scene-designer .lines" v-if="active && targetScene">
|
||||||
|
<OffsetLine :x1="targetScene.vd.x1" :y1="targetScene.vd.y1"
|
||||||
|
:x2="modelValue.__this.vd.x1" :y2="modelValue.__this.vd.y1" :o1="88" :o2="55"
|
||||||
|
class="scene-switcher" marker-start="url(#arrow)" ></OffsetLine>
|
||||||
|
</teleport>
|
||||||
<v-card v-if="selected" :title="modelValue.title" class="mx-2" variant="text">
|
<v-card v-if="selected" :title="modelValue.title" class="mx-2" variant="text">
|
||||||
<asset-selector @select="assignGameObject" :type="['GameObject']">
|
<v-select label="Game Object Type" v-model="modelValue.type" density="compact" hide-details
|
||||||
<template v-slot:activator="props">
|
:items="InteractiveObjectTypes.map(e=>({title: e.name, value: e.id}))"></v-select>
|
||||||
<v-btn v-bind="props" prepend-icon="mdi-panorama-outline" color="success" block>Choose game object</v-btn>
|
|
||||||
</template>
|
|
||||||
</asset-selector>
|
|
||||||
<v-form class="pt-4">
|
<v-form class="pt-4">
|
||||||
<v-text-field density="compact" :label="l.name" v-model="modelValue.title"></v-text-field>
|
<v-text-field density="compact" :label="l.name" v-model="modelValue.title"></v-text-field>
|
||||||
<!-- <v-text-field density="compact" :label="l.id" v-model="modelValue.id"></v-text-field> -->
|
<!-- <v-text-field density="compact" :label="l.id" v-model="modelValue.id"></v-text-field> -->
|
||||||
@@ -35,10 +37,10 @@
|
|||||||
<v-number-input density="compact" label="Level score should be above" v-model="modelValue.activationScore"></v-number-input>
|
<v-number-input density="compact" label="Level score should be above" v-model="modelValue.activationScore"></v-number-input>
|
||||||
<v-select density="compact" label="Following elements should be completed" v-model="modelValue.activationTriggers"
|
<v-select density="compact" label="Following elements should be completed" v-model="modelValue.activationTriggers"
|
||||||
:items="parent.data.items.filter(v=>!v.data.exclude && v.data!==modelValue).map(v=>({title: v.data.title, value: v.data.id}))" multiple ></v-select>
|
:items="parent.data.items.filter(v=>!v.data.exclude && v.data!==modelValue).map(v=>({title: v.data.title, value: v.data.id}))" multiple ></v-select>
|
||||||
|
<v-select label="Activation Type" :items="activationTypes" density="compact" v-model="modelValue.activationType"></v-select>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-card>
|
</v-card>
|
||||||
|
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -52,24 +54,18 @@ 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';
|
||||||
|
import SceneSwitcher from '../InteractiveObjects/SceneSwitcher.vue';
|
||||||
import OffsetLine from './OffsetLine.vue';
|
import OffsetLine from './OffsetLine.vue';
|
||||||
|
|
||||||
|
import { InteractiveObjectTypes } from '../InteractiveObjects/InteractiveObject';
|
||||||
|
|
||||||
|
const components = {
|
||||||
|
SvgIcon, OffsetLine, GenericObject, CharacterObject, VideoPlayer, SceneSwitcher,
|
||||||
|
PuzzleGame1, PuzzleGame2, MazeQuizGame, Particles, ClassicPuzzle
|
||||||
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
emits:['target', 'preview'],
|
emits:['target', 'preview'],
|
||||||
components: {
|
|
||||||
SvgIcon, OffsetLine, GenericObject, CharacterObject, VideoPlayer,
|
|
||||||
PuzzleGame1, PuzzleGame2, MazeQuizGame, Particles, ClassicPuzzle
|
|
||||||
},
|
|
||||||
data(){
|
|
||||||
return {
|
|
||||||
active: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted(){
|
|
||||||
this.active = true;
|
|
||||||
this.modelValue.points ??= 10;
|
|
||||||
this.modelValue.activationScore ??= 0;
|
|
||||||
},
|
|
||||||
props:{
|
props:{
|
||||||
//context: Object,
|
//context: Object,
|
||||||
modelValue: Object,
|
modelValue: Object,
|
||||||
@@ -79,6 +75,23 @@ export default {
|
|||||||
visible: Boolean,
|
visible: Boolean,
|
||||||
parent: Object
|
parent: Object
|
||||||
},
|
},
|
||||||
|
components,
|
||||||
|
data(){
|
||||||
|
return {
|
||||||
|
InteractiveObjectTypes,
|
||||||
|
active: false,
|
||||||
|
activationTypes: [{ title:'Unlock', value:'unlock'}, { title:'Appear', value:'appear'}]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted(){
|
||||||
|
this.active = true;
|
||||||
|
this.modelValue.points ??= 10;
|
||||||
|
this.modelValue.activationScore ??= 0;
|
||||||
|
this.modelValue.type ??= 'GenericObject';
|
||||||
|
if (components[this.modelValue.type].__transform){
|
||||||
|
components[this.modelValue.type].__transform(this.modelValue)
|
||||||
|
}
|
||||||
|
},
|
||||||
computed:{
|
computed:{
|
||||||
showInView(){
|
showInView(){
|
||||||
this.vd.__showInView = this.visible && this.parent.visible;
|
this.vd.__showInView = this.visible && this.parent.visible;
|
||||||
@@ -86,7 +99,10 @@ export default {
|
|||||||
},
|
},
|
||||||
mv(){
|
mv(){
|
||||||
return this.modelValue
|
return this.modelValue
|
||||||
}
|
},
|
||||||
|
targetScene(){
|
||||||
|
return this.modelValue.__root.scenes.find(s=>s.data.id == this.modelValue?.switchScene)
|
||||||
|
},
|
||||||
},
|
},
|
||||||
steps: [['x1', 'y1']],
|
steps: [['x1', 'y1']],
|
||||||
name: 'game-object',
|
name: 'game-object',
|
||||||
@@ -94,17 +110,6 @@ export default {
|
|||||||
methods:{
|
methods:{
|
||||||
intersect(v){
|
intersect(v){
|
||||||
return Utils.intersectPointRect([this.vd.x1, this.vd.y1], 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
|
|
||||||
}
|
|
||||||
if (e.type == 'InteractiveObject'){
|
|
||||||
this.modelValue.type = e.id;
|
|
||||||
}else{
|
|
||||||
this.modelValue.type = 'GenericObject'
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,7 +106,9 @@ export default {
|
|||||||
})
|
})
|
||||||
|
|
||||||
for (let i of scene.data.items || []) {
|
for (let i of scene.data.items || []) {
|
||||||
promises.push(this.$api.gameObject.load(i.data.go).then(r=>i.data.$go = r.data));
|
Object.keys(i.data).filter(k=>k == 'go' || k.startsWith('go_')).forEach(k=>{
|
||||||
|
promises.push(this.$api.gameObject.load(i.data[k]).then(r=>i.data['$'+k] = r.data));
|
||||||
|
})
|
||||||
}
|
}
|
||||||
await Promise.all(promises);
|
await Promise.all(promises);
|
||||||
},
|
},
|
||||||
@@ -193,15 +195,19 @@ export default {
|
|||||||
let idx = di.data.activationTriggers.indexOf(i.data.id)
|
let idx = di.data.activationTriggers.indexOf(i.data.id)
|
||||||
di.data.activationTriggers.splice(idx, 1);
|
di.data.activationTriggers.splice(idx, 1);
|
||||||
}
|
}
|
||||||
if (!di.data.activationTriggers?.length && di.__io.object.__locked &&
|
if (!di.data.activationTriggers?.length && di.__io.object.__active === false &&
|
||||||
gameEngine.dashboard.points > di.data.activationScore){
|
gameEngine.dashboard.points > di.data.activationScore){
|
||||||
di.__io.locker.unlock();
|
di.__io.activator.activate();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (finished == expectToFinish){
|
if (finished == expectToFinish){
|
||||||
//GO TO NEXT LEVEL
|
//GO TO NEXT LEVEL
|
||||||
console.log('LEVEL FINISHED')
|
console.log('LEVEL FINISHED')
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
io.addEventListener('sceneSwitch', (e)=>{
|
||||||
|
console.log(e);
|
||||||
|
this.scenesList = [this.scenes.find(s=>s.data.id == e.scene)]
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
loaded += 1/this.scene.data.items.length
|
loaded += 1/this.scene.data.items.length
|
||||||
|
|||||||
Reference in New Issue
Block a user