particle system as interactive object
This commit is contained in:
@@ -0,0 +1,11 @@
|
|||||||
|
class GenericObject{
|
||||||
|
constructor(engine, data){
|
||||||
|
return new Promise(async(resolve, reject)=>{
|
||||||
|
this.source = await engine.load(data.$go.asset.name);
|
||||||
|
this.object = this.source.scene;
|
||||||
|
resolve(this);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {GenericObject}
|
||||||
@@ -1,10 +1,28 @@
|
|||||||
<template>
|
<template>
|
||||||
|
<div>
|
||||||
|
<v-textarea :label="l.description" v-model="modelValue.description"></v-textarea>
|
||||||
|
<v-checkbox v-model="modelValue.hud" label="Observe in head-up display"></v-checkbox>
|
||||||
|
<v-img :src="`/asset/thumb/${modelValue.go}.webp`" />
|
||||||
|
<div class="text-caption text-center">{{ modelValue.title }}</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
//for now this will be dummy
|
data(){
|
||||||
|
return {
|
||||||
|
active: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted(){
|
||||||
|
this.active = true;
|
||||||
|
},
|
||||||
|
props:{
|
||||||
|
modelValue: Object
|
||||||
|
},
|
||||||
|
methods:{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
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 }
|
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
import { Group } from "three";
|
import { Group } from "three";
|
||||||
|
|
||||||
|
import { GenericObject } from "./GenenricObject";
|
||||||
import { PuzzleGame1 } from "./PuzzleGame1";
|
import { PuzzleGame1 } from "./PuzzleGame1";
|
||||||
import { PuzzleGame2 } from "./PuzzleGame2";
|
import { PuzzleGame2 } from "./PuzzleGame2";
|
||||||
// import { Game3 } from "./games/Game3";
|
// import { Game3 } from "./games/Game3";
|
||||||
@@ -9,9 +11,10 @@ import { TextObject } from "./TextObject";
|
|||||||
import { ImageObject } from "./ImageObject";
|
import { ImageObject } from "./ImageObject";
|
||||||
import { VideoPlayer } from "./VideoPlayer";
|
import { VideoPlayer } from "./VideoPlayer";
|
||||||
import { MazeQuizGame } from "./MazeQuizGame/MazeQuizGame";
|
import { MazeQuizGame } from "./MazeQuizGame/MazeQuizGame";
|
||||||
|
import { Particles } from "./Particles";
|
||||||
import { assignMaterial, assignParams } from "@/lib/MeshUtils";
|
import { assignMaterial, assignParams } from "@/lib/MeshUtils";
|
||||||
|
|
||||||
const games = {PuzzleGame1, PuzzleGame2, PuzzleGame4, MazeQuizGame};
|
const InteractiveObjectsImports = { PuzzleGame1, PuzzleGame2, PuzzleGame4, MazeQuizGame, Particles };
|
||||||
|
|
||||||
class InteractiveObject {
|
class InteractiveObject {
|
||||||
constructor(obj, gameEngine, params) {
|
constructor(obj, gameEngine, params) {
|
||||||
@@ -58,14 +61,15 @@ class InteractiveObject {
|
|||||||
this.source = gltf;
|
this.source = gltf;
|
||||||
break;
|
break;
|
||||||
case 'GenericObject':
|
case 'GenericObject':
|
||||||
this.source = await gameEngine.load(obj.$go.asset.name);
|
let go = await new GenericObject(gameEngine, obj) //await gameEngine.load(obj.$go.asset.name);
|
||||||
this.object = this.source.scene;
|
this.source = go.source;
|
||||||
|
this.object = go.object;
|
||||||
break;
|
break;
|
||||||
case 'PuzzleGame3':
|
case 'PuzzleGame3':
|
||||||
case 'PuzzleGame4':
|
case 'PuzzleGame4':
|
||||||
case 'PuzzleGame5':
|
case 'PuzzleGame5':
|
||||||
case 'PuzzleGame6':
|
case 'PuzzleGame6':
|
||||||
let game = new games[obj.type](gameEngine, obj.args[0], obj.args[1], obj.args[2]);
|
let game = new InteractiveObjectsImports[obj.type](gameEngine, obj.args[0], obj.args[1], obj.args[2]);
|
||||||
this.object = game.object;
|
this.object = game.object;
|
||||||
this.object.game = game;
|
this.object.game = game;
|
||||||
break;
|
break;
|
||||||
@@ -77,7 +81,8 @@ class InteractiveObject {
|
|||||||
case 'PuzzleGame1':
|
case 'PuzzleGame1':
|
||||||
case 'PuzzleGame2':
|
case 'PuzzleGame2':
|
||||||
case 'MazeQuizGame':
|
case 'MazeQuizGame':
|
||||||
this.source = await new games[obj.type](gameEngine, obj);
|
case 'Particles':
|
||||||
|
this.source = await new InteractiveObjectsImports[obj.type](gameEngine, obj);
|
||||||
this.object = this.source.object;
|
this.object = this.source.object;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -96,7 +101,9 @@ const InteractiveObjectTypes = [
|
|||||||
id: 'MazeQuizGame', name: 'Maze Quiz Game'
|
id: 'MazeQuizGame', name: 'Maze Quiz Game'
|
||||||
},{
|
},{
|
||||||
id: 'VideoPlayer', name: 'Video Player'
|
id: 'VideoPlayer', name: 'Video Player'
|
||||||
|
},{
|
||||||
|
id: 'Particles', name: 'Particles'
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
export { InteractiveObject, InteractiveObjectTypes }
|
export { InteractiveObject, InteractiveObjectTypes, InteractiveObjectsImports }
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
import {
|
||||||
|
Matrix4,
|
||||||
|
Mesh,
|
||||||
|
PlaneGeometry,
|
||||||
|
MeshPhongMaterial,
|
||||||
|
Vector3,
|
||||||
|
} from 'three';
|
||||||
|
|
||||||
|
import * as BufferGeometryUtils from 'three/addons/utils/BufferGeometryUtils.js';
|
||||||
|
|
||||||
|
class Particles {
|
||||||
|
constructor(engine, data) {
|
||||||
|
const { x, y, count, w, h } = data;
|
||||||
|
let positions = Particles.positions(count, w, h);
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
let t = await engine.loadTexture(data.$go.asset.name)
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.object = new Mesh(BufferGeometryUtils.mergeGeometries(arr, false), material);
|
||||||
|
resolve(this);
|
||||||
|
arr.forEach(g => g.dispose());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
static positions(count, x, z) {
|
||||||
|
let 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 { Particles }
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
<template>
|
||||||
|
<v-card v-if="modelValue.go">
|
||||||
|
<v-card-item>
|
||||||
|
<v-number-input density="compact" :precision="null" label="Particle width" v-model="modelValue.x"></v-number-input>
|
||||||
|
<v-number-input density="compact" :precision="null" label="Particle height" v-model="modelValue.y"></v-number-input>
|
||||||
|
|
||||||
|
<v-number-input density="compact" :precision="null" label="Area width" v-model="modelValue.w"></v-number-input>
|
||||||
|
<v-number-input density="compact" :precision="null" label="Area length" v-model="modelValue.h"></v-number-input>
|
||||||
|
|
||||||
|
<v-number-input density="compact" label="Count" v-model="modelValue.count"></v-number-input>
|
||||||
|
|
||||||
|
<v-img :src="`/asset/thumb/${modelValue.go}.webp`" />
|
||||||
|
<div class="text-caption text-center">{{ modelValue.title }}</div>
|
||||||
|
</v-card-item>
|
||||||
|
</v-card>
|
||||||
|
<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>
|
||||||
|
//Grass.positions(1000,50,50), '/static/textures/grass01.png', 1, .5
|
||||||
|
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.x = 1;
|
||||||
|
this.modelValue.y = 1;
|
||||||
|
this.modelValue.count = 1000;
|
||||||
|
this.modelValue.w = 50;
|
||||||
|
this.modelValue.h = 50;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -18,7 +18,6 @@
|
|||||||
</asset-selector>
|
</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-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-text-field density="compact" :label="l.id" v-model="modelValue.id"></v-text-field>
|
||||||
</v-form>
|
</v-form>
|
||||||
</v-card>
|
</v-card>
|
||||||
@@ -36,11 +35,12 @@ 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 Particles from '../InteractiveObjects/Particles.vue';
|
||||||
import GenericObject from '../InteractiveObjects/GenericObject.vue';
|
import GenericObject from '../InteractiveObjects/GenericObject.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
emits:['target', 'preview'],
|
emits:['target', 'preview'],
|
||||||
components: { SvgIcon, VideoPlayer, PuzzleGame1, PuzzleGame2, MazeQuizGame, GenericObject },
|
components: { SvgIcon, GenericObject, VideoPlayer, PuzzleGame1, PuzzleGame2, MazeQuizGame, Particles, },
|
||||||
data(){
|
data(){
|
||||||
return {
|
return {
|
||||||
active: false
|
active: false
|
||||||
|
|||||||
@@ -16,9 +16,8 @@ export class CharacterControls {
|
|||||||
walkVelocity = 7
|
walkVelocity = 7
|
||||||
lerp = (x, y, a) => x * (1 - a) + y * a;
|
lerp = (x, y, a) => x * (1 - a) + y * a;
|
||||||
|
|
||||||
constructor(model, mixer, animationsMap, engine, currentAction, po, pointerControls) {
|
constructor(model, animationsMap, engine, currentAction, po, pointerControls) {
|
||||||
this.model = model
|
this.model = model
|
||||||
this.mixer = mixer
|
|
||||||
this.animationsMap = animationsMap
|
this.animationsMap = animationsMap
|
||||||
this.currentAction = currentAction
|
this.currentAction = currentAction
|
||||||
this.animationsMap[currentAction].play()
|
this.animationsMap[currentAction].play()
|
||||||
@@ -91,14 +90,13 @@ export class CharacterControls {
|
|||||||
const current = this.animationsMap[this.currentAction]
|
const current = this.animationsMap[this.currentAction]
|
||||||
|
|
||||||
current.fadeOut(this.fadeDuration)
|
current.fadeOut(this.fadeDuration)
|
||||||
toPlay.timeScale = 0.5;
|
//toPlay.timeScale = 1;
|
||||||
toPlay.reset().fadeIn(this.fadeDuration).play();
|
toPlay.reset().fadeIn(this.fadeDuration).play();
|
||||||
|
|
||||||
this.currentAction = play
|
this.currentAction = play
|
||||||
this.actionStart = 0;
|
this.actionStart = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.mixer.update(delta)
|
|
||||||
this.actionStart += delta;
|
this.actionStart += delta;
|
||||||
|
|
||||||
this.cameraDelta += delta * ( pointerControls.cameraLeft * -1 + pointerControls.cameraRight * 1)
|
this.cameraDelta += delta * ( pointerControls.cameraLeft * -1 + pointerControls.cameraRight * 1)
|
||||||
@@ -150,11 +148,6 @@ export class CharacterControls {
|
|||||||
|
|
||||||
cameraPosition.lerp(cameraDesiredPosition, delta*2)
|
cameraPosition.lerp(cameraDesiredPosition, delta*2)
|
||||||
this.camera.position.copy(cameraPosition)
|
this.camera.position.copy(cameraPosition)
|
||||||
// this.camera.lookAt(new THREE.Vector3(
|
|
||||||
// this.model.position.x,
|
|
||||||
// 2,
|
|
||||||
// this.model.position.z
|
|
||||||
// ))
|
|
||||||
this.orbitControl.target.set(this.model.position.x, 2, this.model.position.z)
|
this.orbitControl.target.set(this.model.position.x, 2, this.model.position.z)
|
||||||
this.camera.lookAt(this.orbitControl.target)
|
this.camera.lookAt(this.orbitControl.target)
|
||||||
}
|
}
|
||||||
@@ -165,4 +158,9 @@ export class CharacterControls {
|
|||||||
pointerControls.moveForward * 1 + pointerControls.moveBackward * -1
|
pointerControls.moveForward * 1 + pointerControls.moveBackward * -1
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
idleReset(){
|
||||||
|
this.actionStart = 0;
|
||||||
|
this.currentAction = 'idle'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -482,6 +482,7 @@ class GameEngine extends THREE.EventDispatcher{
|
|||||||
let mouse = this.getMouseVector(mouseEvent, domElement);
|
let mouse = this.getMouseVector(mouseEvent, domElement);
|
||||||
this.raycaster.setFromCamera(mouse, this.camera);
|
this.raycaster.setFromCamera(mouse, this.camera);
|
||||||
this.clickable.update(mouse, this.camera, mouseEvent);
|
this.clickable.update(mouse, this.camera, mouseEvent);
|
||||||
|
this.hero?.characterControls?.idleReset();
|
||||||
}
|
}
|
||||||
|
|
||||||
autoScale(object, mk = 1) {
|
autoScale(object, mk = 1) {
|
||||||
|
|||||||
+1
-1
@@ -31,7 +31,7 @@ class Hero{
|
|||||||
po.collider.setTranslationWrtParent({ x: 0, y: 2.0, z: 0 });
|
po.collider.setTranslationWrtParent({ x: 0, y: 2.0, z: 0 });
|
||||||
//po.collider.setActiveEvents(RAPIER.ActiveEvents.COLLISION_EVENTS);
|
//po.collider.setActiveEvents(RAPIER.ActiveEvents.COLLISION_EVENTS);
|
||||||
|
|
||||||
this.characterControls = new CharacterControls(this.model, this.mixer,
|
this.characterControls = new CharacterControls(this.model,
|
||||||
this.animationsMap, gameEngine, 'idle', po, this.pointerControls)
|
this.animationsMap, gameEngine, 'idle', po, this.pointerControls)
|
||||||
|
|
||||||
this.clock = new THREE.Clock()
|
this.clock = new THREE.Clock()
|
||||||
|
|||||||
Reference in New Issue
Block a user