game designer
This commit is contained in:
@@ -62,7 +62,7 @@ class GamesController{
|
||||
* @memberof GamesController
|
||||
*/
|
||||
router.delete('/:id', async (req, res)=>{
|
||||
await scenario.remove(req.params.id);
|
||||
await game.remove(req.params.id);
|
||||
res.json({status: 'OK'});
|
||||
})
|
||||
|
||||
|
||||
Generated
+12
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "pronature-platform",
|
||||
"version": "0.0.0",
|
||||
"version": "0.2.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "pronature-platform",
|
||||
"version": "0.0.0",
|
||||
"version": "0.2.0",
|
||||
"dependencies": {
|
||||
"@mdi/font": "7.4.47",
|
||||
"@vitejs/plugin-basic-ssl": "^1.1.0",
|
||||
@@ -25,6 +25,7 @@
|
||||
"roboto-fontface": "*",
|
||||
"sharp": "^0.33.5",
|
||||
"three": "^0.169.0",
|
||||
"three-viewport-gizmo": "^2.2.0",
|
||||
"uuid": "^11.0.2",
|
||||
"vue": "^3.5.13",
|
||||
"vuetify": "^3.7.16"
|
||||
@@ -6623,6 +6624,15 @@
|
||||
"integrity": "sha512-Ed906MA3dR4TS5riErd4QBsRGPcx+HBDX2O5yYE5GqJeFQTPU+M56Va/f/Oph9X7uZo3W3o4l2ZhBZ6f6qUv0w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/three-viewport-gizmo": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/three-viewport-gizmo/-/three-viewport-gizmo-2.2.0.tgz",
|
||||
"integrity": "sha512-Jo9Liur1rUmdKk75FZumLU/+hbF+RtJHi1qsKZpntjKlCYScK6tjbYoqvJ9M+IJphrlQJF5oReFW7Sambh0N4Q==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"three": ">=0.162.0 <1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/through": {
|
||||
"version": "2.3.8",
|
||||
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
"roboto-fontface": "*",
|
||||
"sharp": "^0.33.5",
|
||||
"three": "^0.169.0",
|
||||
"three-viewport-gizmo": "^2.2.0",
|
||||
"uuid": "^11.0.2",
|
||||
"vue": "^3.5.13",
|
||||
"vuetify": "^3.7.16"
|
||||
|
||||
@@ -1,18 +1,48 @@
|
||||
<template>
|
||||
<v-btn-toggle variant="tonal" density="compact" class="mx-auto" v-model="mode" color="blue">
|
||||
<!-- <v-btn size="small" class="text-none" value="default"
|
||||
prepend-icon="mdi-cursor-default-click">Pointer</v-btn> -->
|
||||
<v-btn size="small" class="text-none" value="translate" prepend-icon="mdi-cursor-move">Move</v-btn>
|
||||
<v-btn size="small" class="text-none" value="rotate" prepend-icon="mdi-rotate-orbit">Rotate</v-btn>
|
||||
<v-btn size="small" class="text-none" value="scale" prepend-icon="mdi-resize">Scale</v-btn>
|
||||
<v-navigation-drawer width="133">
|
||||
<v-btn-toggle variant="tonal" density="comfortable" class="ma-3" v-model="renderType" color="light-blue-darken-4">
|
||||
<v-btn value="ST" icon="mdi-video-3d-variant"></v-btn>
|
||||
<v-btn value="VR" icon="mdi-google-cardboard"></v-btn>
|
||||
<v-btn value="AG" icon="mdi-glasses"></v-btn>
|
||||
</v-btn-toggle>
|
||||
<div class="container my-3">
|
||||
<v-btn-toggle variant="tonal" density="comfortable" class="ma-3" v-model="mode" color="green-darken-4">
|
||||
<v-btn class="text-none" value="translate" icon="mdi-cursor-move"></v-btn>
|
||||
<v-btn class="text-none" value="rotate" icon="mdi-rotate-orbit"></v-btn>
|
||||
<v-btn class="text-none" value="scale" icon="mdi-resize"></v-btn>
|
||||
</v-btn-toggle>
|
||||
<v-btn-toggle variant="tonal" v-model="cameraType" class="ma-3" density="comfortable" color="orange-darken-4">
|
||||
<v-btn value="perspective" icon="mdi-cone"></v-btn>
|
||||
<v-btn value="orthographic" icon="mdi-cone-off"></v-btn>
|
||||
</v-btn-toggle>
|
||||
</v-navigation-drawer>
|
||||
<div class="container my-3 position-relative game-designer-canvas">
|
||||
<div ref="target" @click="targetClick" @pointerdown="targetPointerDown"></div>
|
||||
<div class="renderer-gizmo"></div>
|
||||
</div>
|
||||
<v-toolbar density="compact">
|
||||
<v-slide-group show-arrows>
|
||||
<v-slide-group-item v-for="(a, i) in objectAnimations" :key="i" v-slot="{ isSelected }">
|
||||
<v-btn :color="isSelected ? 'primary' : undefined" class="ma-2"
|
||||
:prepend-icon="'mdi-' + (a.playing ? 'stop' : 'play')" rounded @click="toggleAnimation(a)">
|
||||
{{ a.name }}
|
||||
</v-btn>
|
||||
</v-slide-group-item>
|
||||
</v-slide-group>
|
||||
</v-toolbar>
|
||||
<v-navigation-drawer location="right">
|
||||
<v-list v-model:selected="scenesList" selectable>
|
||||
<v-list v-model:selected="scenesList" selectable color="primary">
|
||||
<v-list-item v-for="(s, i) in scenes" :key="i" :title="s.data.title" :value="s"></v-list-item>
|
||||
</v-list>
|
||||
<v-list selectable v-model:selected="objectsList" color="secondary">
|
||||
<v-list-item v-for="(v, k) in sceneObjects" :title="v.__title" :subtitle="k" :value=v>
|
||||
<template v-slot:prepend>
|
||||
<v-btn variant="plain" density="comfortable" size="small" v-if="v.__o"
|
||||
:icon="`mdi-eye${v.__o.visible ? '' : '-off'}`"
|
||||
@click.stop="v.__o.visible = !v.__o.visible"></v-btn>
|
||||
<!-- <v-icon :icon="components[item.name].icon" size="small"></v-icon> -->
|
||||
</template>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-navigation-drawer>
|
||||
</template>
|
||||
|
||||
@@ -25,70 +55,114 @@ let gameEngine = null;
|
||||
export default {
|
||||
props:{
|
||||
modelValue: Object,
|
||||
scenario: Object
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
scenesList: [],
|
||||
objectsList: [],
|
||||
mode: 'translate',
|
||||
pointerDownTime: 0
|
||||
pointerDownTime: 0,
|
||||
scenario: null,
|
||||
renderType: 'ST',
|
||||
cameraType: 'perspective'
|
||||
}
|
||||
},
|
||||
computed:{
|
||||
scenes(){
|
||||
return this.scenario.scenes || [];
|
||||
return this.scenario?.scenes || [];
|
||||
},
|
||||
scene(){
|
||||
return this.scenesList[0];
|
||||
},
|
||||
currentObject(){
|
||||
return this.objectsList[0];
|
||||
},
|
||||
sceneObjects(){
|
||||
return this.object.scenes?.[this.scene?.data?.id]?.objects;
|
||||
},
|
||||
object(){
|
||||
return this.modelValue;
|
||||
},
|
||||
objectAnimations(){
|
||||
return this.currentObject?.__g?.animations?.map(a => ({
|
||||
name: a.name, id: a.uuid, a
|
||||
}));
|
||||
}
|
||||
},
|
||||
watch:{
|
||||
async scene(n){
|
||||
await this.loadEnvironment();
|
||||
this.object.scenes = this.object.scenes || {}
|
||||
this.object.scenes[n.data.id] = this.object.scenes[n.data.id] || {}
|
||||
await this.loadEnvironment(n, this.object.scenes[n.data.id]);
|
||||
},
|
||||
mode(n){
|
||||
gameEngine.transformControls.setMode(n)
|
||||
},
|
||||
async 'object.scenario'(n){
|
||||
await this.loadScenario()
|
||||
},
|
||||
currentObject(n){
|
||||
gameEngine.transformControls.attach(n.__o);
|
||||
gameEngine.gizmo.target = n.__o.position;
|
||||
},
|
||||
renderType(v){
|
||||
gameEngine.renderType = v;
|
||||
},
|
||||
cameraType(v){
|
||||
if (v == 'perspective'){
|
||||
gameEngine.setCameraPerspective();
|
||||
}else{
|
||||
gameEngine.setCameraOrthographic();
|
||||
}
|
||||
}
|
||||
},
|
||||
async mounted(){
|
||||
gameEngine = new GameEngine();
|
||||
this.gameEngine = gameEngine;
|
||||
//this.gameEngine = gameEngine;
|
||||
await gameEngine.init(this.$refs.target);
|
||||
gameEngine.scene.add(gameEngine.transformControls.getHelper())
|
||||
gameEngine.scene.add(gameEngine.transformControls.getHelper());
|
||||
gameEngine.scene.add(new gameEngine.$.GridHelper(100,100));
|
||||
this.resize();
|
||||
//gameEngine.setCamera(gameEngine.orthographicCamera)
|
||||
//gameEngine.setCameraOrthographic();
|
||||
await this.loadScenario();
|
||||
window.addEventListener('resize', this.resize);
|
||||
},
|
||||
unmounted(){
|
||||
window,removeEventListener('resize', this.resize);
|
||||
},
|
||||
methods:{
|
||||
async loadEnvironment(){
|
||||
await this.expandScenarioData();
|
||||
if (!this.object.gd){
|
||||
this.object.gd = {
|
||||
items: []
|
||||
};
|
||||
async loadScenario(){
|
||||
if (this.object.scenario){
|
||||
this.scenario = (await this.$api.scenario.load(this.object.scenario)).data;
|
||||
}else{
|
||||
this.scenario = null;
|
||||
}
|
||||
},
|
||||
async loadEnvironment(scene, target){
|
||||
//await gameEngine.loadPanorama(`/asset/default/43.webp`);
|
||||
await this.expandScenarioData(scene);
|
||||
target.objects = target.objects || {};
|
||||
let l = target.objects;
|
||||
if (this.scene.data.$environment.type == 'panorama2d'){
|
||||
await gameEngine.loadPanorama(`/asset/default/${this.scene.data.$environment.asset.name}`);
|
||||
}else{
|
||||
let env = await gameEngine.load(`/asset/default/${this.scene.data.$environment.asset.name}`);
|
||||
gameEngine.autoScale(env.scene, 10);
|
||||
this.setObjectAttributes(l, this.scene.data, env, 100);
|
||||
gameEngine.activeObjects.add(env.scene);
|
||||
}
|
||||
for (let i of this.scene.data.items) {
|
||||
let gltf = await gameEngine.load(`/asset/default/${i.data.$go.asset.name}`);
|
||||
let o = gltf.scene;
|
||||
gameEngine.autoScale(o);
|
||||
gameEngine.activeObjects.add(o);
|
||||
const {position, scale, rotation} = o;
|
||||
i.gd = {position, scale, rotation};
|
||||
console.log(JSON.stringify(i.gd));
|
||||
window.gameEngine = gameEngine;
|
||||
this.setObjectAttributes(l, i.data, gltf, 10);
|
||||
gameEngine.activeObjects.add(gltf.scene);
|
||||
//console.log(JSON.stringify(l));
|
||||
//window.gameEngine = gameEngine;
|
||||
//console.log(new gameEngine.$.Euler({"isEuler":true,"_x":0,"_y":0,"_z":0,"_order":"XYZ"}));
|
||||
}
|
||||
},
|
||||
async expandScenarioData(){
|
||||
this.scene.data.$environment = (await this.$api.gameObject.load(this.scene.data.environment)).data
|
||||
for (let i of this.scene.data.items) {
|
||||
async expandScenarioData(scene){
|
||||
scene.data.$environment = (await this.$api.gameObject.load(scene.data.environment)).data
|
||||
for (let i of scene.data.items) {
|
||||
i.data.$go = (await this.$api.gameObject.load(i.data.go)).data;
|
||||
}
|
||||
},
|
||||
@@ -99,13 +173,41 @@ export default {
|
||||
if (performance.now() - this.pointerDownTime < 200){
|
||||
let intersects = gameEngine.intersect(e, this.$refs.target, gameEngine.activeObjects.children, true);
|
||||
if (intersects.length){
|
||||
console.log('attaching controls to', intersects[0].object)
|
||||
gameEngine.transformControls.attach(intersects[0].object);
|
||||
//console.log('attaching controls to', intersects[0].object)
|
||||
//gameEngine.transformControls.attach(intersects[0].object);
|
||||
console.log(this.sceneObjects[intersects[0].object.__pn_id])
|
||||
this.objectsList[0] = this.sceneObjects[intersects[0].object.__pn_id]
|
||||
}else{
|
||||
gameEngine.transformControls.detach();
|
||||
}
|
||||
}
|
||||
},
|
||||
setObjectAttributes(l, data, o, autoScaleFactor = 1){
|
||||
if (l[data.id]){
|
||||
['position', 'scale', 'rotation'].forEach(p=>{
|
||||
o.scene[p].copy(l[data.id][p])
|
||||
})
|
||||
}else{
|
||||
gameEngine.autoScale(o.scene, autoScaleFactor);
|
||||
}
|
||||
l[data.id] = l[data.id] || {};
|
||||
['position', 'scale', 'rotation', 'visible'].forEach(p=>{
|
||||
l[data.id][p] = o.scene[p];
|
||||
})
|
||||
l[data.id].__o = o.scene;
|
||||
l[data.id].__g = o;
|
||||
l[data.id].__title = data.title;
|
||||
o.scene.__pn_id = data.id;
|
||||
},
|
||||
async toggleAnimation(animation){
|
||||
animation.playing = !animation.playing;
|
||||
gameEngine.playAnimation(gameEngine.scene, animation.a, animation.playing);
|
||||
},
|
||||
resize(){
|
||||
let r = this.$refs.target;
|
||||
gameEngine.resize(r.clientWidth, r.clientHeight);
|
||||
//this.zoom = Math.min(r.clientWidth / this.viewBox.w, r.clientHeight / this.viewBox.h);
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -19,6 +19,7 @@
|
||||
<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>
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
<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>
|
||||
|
||||
@@ -11,15 +11,17 @@
|
||||
</g>
|
||||
</teleport>
|
||||
<v-card v-if="selected" :title="modelValue.title" class="mx-2" variant="text">
|
||||
<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-form>
|
||||
<asset-selector @select="assignTaskIntro" type="Descriptive">
|
||||
<template v-slot:activator="props">
|
||||
<v-btn v-bind="props" prepend-icon="mdi-panorama-outline" color="success" block>Choose task description</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>
|
||||
|
||||
|
||||
+120
-23
@@ -1,33 +1,42 @@
|
||||
import * as THREE from 'three';
|
||||
import { GLTFLoader } from 'three/examples/jsm/Addons.js';
|
||||
import { OrbitControls } from 'three/examples/jsm/Addons.js';
|
||||
import { ViewportGizmo } from "three-viewport-gizmo";
|
||||
//import { AnaglyphEffect } from './three/AnaglyphEffect';
|
||||
import { AnaglyphEffect } from 'three/addons/effects/AnaglyphEffect.js';
|
||||
import { StereoEffect } from 'three/addons/effects/StereoEffect.js';
|
||||
import { MapControls } from 'three/addons/controls/MapControls.js';
|
||||
import { FirstPersonControls } from 'three/addons/controls/FirstPersonControls.js';
|
||||
import { TransformControls } from 'three/addons/controls/TransformControls.js';
|
||||
|
||||
class GameEngine {
|
||||
async init(domNode) {
|
||||
const width = 1200, height = 800;
|
||||
this.w = domNode.clientWidth || 1200, this.h = domNode.clientHeight || 800;
|
||||
this.aspect = this.w / this.h
|
||||
const gameEngine = this;
|
||||
|
||||
const camera = new THREE.PerspectiveCamera(70, width / height, 0.01, 10000);
|
||||
this.perspectiveCamera = new THREE.PerspectiveCamera(50, this.aspect, 0.01, 1000);
|
||||
this.raycaster = new THREE.Raycaster();
|
||||
camera.position.set(1, 0, 1);
|
||||
this.perspectiveCamera.position.set(0, 0, 10);
|
||||
|
||||
this.camera = this.perspectiveCamera;
|
||||
|
||||
this.frustumSize = 50;
|
||||
this.orthographicCamera = new THREE.OrthographicCamera(
|
||||
this.frustumSize * this.aspect / - 2,
|
||||
this.frustumSize * this.aspect / 2,
|
||||
this.frustumSize / 2,
|
||||
this.frustumSize / - 2,
|
||||
0.01, 1000);
|
||||
this.orthographicCamera.position.set( 0, 0, 100 );
|
||||
const scene = new THREE.Scene();
|
||||
// this.light = new THREE.AmbientLight( 0x404040, 0 ); // soft white light
|
||||
// scene.add( this.light );
|
||||
|
||||
function animate(time) {
|
||||
let delta = clock.getDelta();
|
||||
mixer.update(delta);
|
||||
renderer.render(scene, camera);
|
||||
controls.update();
|
||||
}
|
||||
|
||||
const renderer = new THREE.WebGLRenderer({
|
||||
antialias: true,
|
||||
alpha: true,
|
||||
preserveDrawingBuffer: true
|
||||
// alpha: true,
|
||||
// preserveDrawingBuffer: true
|
||||
});
|
||||
renderer.setPixelRatio( window.devicePixelRatio );
|
||||
// renderer.toneMapping = THREE.CineonToneMapping;
|
||||
@@ -35,16 +44,42 @@ class GameEngine {
|
||||
// renderer.shadowMap.enabled = true;
|
||||
// renderer.shadowMap.type = THREE.PCFSoftShadowMap; // default THREE.PCFShadowMap
|
||||
renderer.outputEncoding = THREE.sRGBEncoding;
|
||||
const controls = new OrbitControls( camera, renderer.domElement );
|
||||
renderer.setSize(this.w, this.h);
|
||||
renderer.setViewport( 0, 0, this.w, this.h );
|
||||
renderer.autoClear = true;
|
||||
|
||||
this.anaglyph = new AnaglyphEffect( renderer );
|
||||
this.anaglyph.setSize( this.w, this.h );
|
||||
|
||||
this.stereo = new StereoEffect(renderer);
|
||||
this.stereo.setSize( this.w, this.h );
|
||||
|
||||
const controls = new OrbitControls( this.camera, renderer.domElement );
|
||||
const gizmo = new ViewportGizmo(this.camera, renderer, {
|
||||
container:'.renderer-gizmo',
|
||||
//type:'cube'
|
||||
});
|
||||
gizmo.attachControls(controls);
|
||||
this.gizmo = gizmo;
|
||||
|
||||
this.orbitControls = controls;
|
||||
//controls.enableZoom = true;
|
||||
//const controls = new MapControls( camera, renderer.domElement );
|
||||
this.transformControls = new TransformControls( camera, renderer.domElement );
|
||||
this.transformControls = new TransformControls( this.camera, renderer.domElement );
|
||||
this.transformControls.addEventListener( 'dragging-changed', function ( event ) {
|
||||
controls.enabled = ! event.value;
|
||||
} );
|
||||
// controls.enableDamping = true;
|
||||
// controls.screenSpacePanning = true;
|
||||
renderer.setSize(width, height);
|
||||
|
||||
this.renderType = 'ST';
|
||||
|
||||
function animate(time) {
|
||||
let delta = clock.getDelta();
|
||||
mixer.update(delta);
|
||||
gameEngine.render(scene, gameEngine.camera);
|
||||
gizmo.render();
|
||||
}
|
||||
renderer.setAnimationLoop(animate);
|
||||
|
||||
const mixer = new THREE.AnimationMixer(this.scene);
|
||||
@@ -54,8 +89,6 @@ class GameEngine {
|
||||
this.renderer = renderer;
|
||||
this.scene = scene;
|
||||
this.loader = new GLTFLoader();
|
||||
this.camera = camera;
|
||||
this.controls = controls;
|
||||
this.mixer = mixer;
|
||||
|
||||
this.activeObjects = new THREE.Group();
|
||||
@@ -72,10 +105,10 @@ class GameEngine {
|
||||
scene.background = new THREE.Color(1,1,1);
|
||||
console.log('GameEngine started')
|
||||
renderer.domElement.addEventListener('wheel', (event)=>{
|
||||
camera.zoom -= event.deltaY / 1000;
|
||||
camera.zoom = Math.max(camera.zoom, .4);
|
||||
controls.rotateSpeed = 1 / camera.zoom;
|
||||
camera.updateProjectionMatrix();
|
||||
gameEngine.camera.zoom -= event.deltaY / 1000;
|
||||
gameEngine.camera.zoom = Math.max(gameEngine.camera.zoom, .4);
|
||||
controls.rotateSpeed = 1 / gameEngine.camera.zoom;
|
||||
gameEngine.camera.updateProjectionMatrix();
|
||||
})
|
||||
}
|
||||
|
||||
@@ -142,8 +175,7 @@ class GameEngine {
|
||||
intersect(mouseEvent, domElement, objects, recursive = false, returnInputObjects = true){
|
||||
let mouse = this.getMouseVector(mouseEvent, domElement);
|
||||
this.raycaster.setFromCamera(mouse, this.camera);
|
||||
console.log(objects)
|
||||
let intersects = this.raycaster.intersectObjects(objects, recursive);
|
||||
let intersects = this.raycaster.intersectObjects(objects.filter(o=>o.visible), recursive);
|
||||
if (returnInputObjects && recursive){
|
||||
intersects.forEach(o=>{
|
||||
while (o.object && !objects.includes(o.object)) {
|
||||
@@ -159,6 +191,71 @@ class GameEngine {
|
||||
let k = Math.max(bb.max.x - bb.min.x, bb.max.y - bb.min.y, bb.max.z - bb.min.z);
|
||||
object.scale.multiplyScalar(mk/k);
|
||||
}
|
||||
|
||||
setCamera(camera){
|
||||
//camera.updateProjectionMatrix();
|
||||
this.camera = camera;
|
||||
//this.transformControls.camera = camera;
|
||||
this.orbitControls.object = camera;
|
||||
}
|
||||
|
||||
setCameraOrthographic() {
|
||||
let o = this.orthographicCamera;
|
||||
// o.position.copy(o.position);
|
||||
// const distance = o.position.distanceTo(this.orbitControls.target);
|
||||
// const halfWidth = this.frustumWidthAtDistance(o, distance) / 2;
|
||||
// const halfHeight = this.frustumHeightAtDistance(o, distance) / 2;
|
||||
// o.top = halfHeight;
|
||||
// o.bottom = -halfHeight;
|
||||
// o.left = -halfWidth;
|
||||
// o.right = halfWidth;
|
||||
// o.zoom = 1;
|
||||
// o.lookAt(this.orbitControls.target);
|
||||
// o.updateProjectionMatrix();
|
||||
this.camera = o;
|
||||
this.transformControls.camera = o;
|
||||
this.orbitControls.object = o;
|
||||
this.gizmo.camera = o;
|
||||
}
|
||||
|
||||
setCameraPerspective() {
|
||||
let o = this.perspectiveCamera;
|
||||
// const oldY = o.position.y;
|
||||
// o.position.copy(o.position);
|
||||
// o.position.y = oldY / o.zoom;
|
||||
// o.updateProjectionMatrix();
|
||||
this.camera = o;
|
||||
this.transformControls.camera = o;
|
||||
this.orbitControls.object = o;
|
||||
this.gizmo.camera = o;
|
||||
}
|
||||
|
||||
resize(w, h){
|
||||
this.w = w;
|
||||
this.h = h;
|
||||
this.aspect = this.w / this.h
|
||||
this.perspectiveCamera.aspect = this.aspect;
|
||||
this.perspectiveCamera.updateProjectionMatrix();
|
||||
this.orthographicCamera.left = - this.frustumSize * this.aspect / 2;
|
||||
this.orthographicCamera.right = this.frustumSize * this.aspect / 2;
|
||||
this.orthographicCamera.top = this.frustumSize / 2;
|
||||
this.orthographicCamera.bottom = - this.frustumSize / 2;
|
||||
this.renderer.setSize(w, h);
|
||||
this.renderer.setViewport( 0, 0, this.w, this.h );
|
||||
this.anaglyph.setSize( w, h );
|
||||
this.stereo.setSize( w, h );
|
||||
this.gizmo.update();
|
||||
}
|
||||
|
||||
render(scene, camera){
|
||||
if (this.renderType == 'VR'){
|
||||
this.stereo?.render( scene, camera );
|
||||
}else if (this.renderType == 'AG'){
|
||||
this.anaglyph?.render( scene, camera );
|
||||
}else{
|
||||
this.renderer.render( scene, camera );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export {GameEngine}
|
||||
@@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<v-container max-width="1400">
|
||||
<v-tabs v-model="panel">
|
||||
<v-tabs v-model="panel" class="mb-2">
|
||||
<v-tab value="game">
|
||||
<v-icon icon="mdi-pencil"></v-icon> {{ id == 'add' ? l.createGame : l.editGame }}
|
||||
</v-tab>
|
||||
<v-tab value="gameDesigner" v-if="scenario">
|
||||
<v-tab value="gameDesigner" v-if="object.scenario">
|
||||
<v-icon icon="mdi-movie-open-outline"></v-icon> {{ l.gameDesigner }}
|
||||
</v-tab>
|
||||
</v-tabs>
|
||||
@@ -17,7 +17,7 @@
|
||||
</v-form>
|
||||
</v-tabs-window-item>
|
||||
<v-tabs-window-item value="gameDesigner">
|
||||
<GameDesigner v-model="object" :scenario="scenario" ref="gameDesigner" ></GameDesigner>
|
||||
<GameDesigner v-model="object" ref="gameDesigner" ></GameDesigner>
|
||||
</v-tabs-window-item>
|
||||
</v-tabs-window>
|
||||
<v-btn @click="save" :loading="loading" prepend-icon="mdi-content-save" color="primary">{{ l.save }}</v-btn>
|
||||
@@ -37,8 +37,7 @@ export default {
|
||||
},
|
||||
loading: false,
|
||||
panel: [],
|
||||
scenarios: [],
|
||||
scenario: null
|
||||
scenarios: []
|
||||
}
|
||||
},
|
||||
async mounted(){
|
||||
@@ -46,26 +45,13 @@ export default {
|
||||
this.object = (await this.$api.game.load(this.id)).data;
|
||||
}
|
||||
this.scenarios = (await this.$api.scenario.search()).data.data;
|
||||
await this.loadScenario()
|
||||
},
|
||||
computed: {
|
||||
id() {
|
||||
return this.$route.params?.id;
|
||||
}
|
||||
},
|
||||
watch:{
|
||||
async 'object.scenario'(n){
|
||||
await this.loadScenario()
|
||||
}
|
||||
},
|
||||
methods:{
|
||||
async loadScenario(){
|
||||
if (this.object.scenario){
|
||||
this.scenario = (await this.$api.scenario.load(this.object.scenario)).data;
|
||||
}else{
|
||||
this.scenario = null;
|
||||
}
|
||||
},
|
||||
async save(params) {
|
||||
this.loading = true;
|
||||
try {
|
||||
|
||||
@@ -6,6 +6,7 @@ const lang = {
|
||||
createGame: 'Add game',
|
||||
editGame: 'Edit game',
|
||||
name: 'Name',
|
||||
id: 'Identifier',
|
||||
description: 'Description',
|
||||
fieldRequired: 'Field is required',
|
||||
objectType: 'Object type',
|
||||
@@ -45,6 +46,7 @@ const lang = {
|
||||
createGame: 'Добавяне на игра',
|
||||
editGame: 'Редактиране на игра',
|
||||
name: 'Име',
|
||||
id: 'Идентификатор',
|
||||
description: 'Описание',
|
||||
fieldRequired: 'Полето е задължително',
|
||||
objectType: 'Тип обект',
|
||||
|
||||
@@ -102,3 +102,9 @@ video{
|
||||
cursor: grabbing;
|
||||
}
|
||||
}
|
||||
|
||||
.game-designer-canvas{
|
||||
width: 100%;
|
||||
max-width: 100vw;
|
||||
height: calc(100vh - 288px);
|
||||
}
|
||||
Reference in New Issue
Block a user