game rules - object triggers set up

This commit is contained in:
2025-11-13 09:17:18 +02:00
parent 2a1423877b
commit c8e501ff6e
9 changed files with 98 additions and 20 deletions
@@ -28,6 +28,7 @@ export default {
assignCharacter(e){
this.modelValue.go = e.id;
this.modelValue.title = e.name
this.modelValue.exclude = true
}
}
}
@@ -1,5 +1,5 @@
import { getBoundingBox, getBoundingBoxCenterPoint, getBoundingBoxMaxLength, centerOrigin } from "@/lib/MeshUtils";
import { EventDispatcher } from "three";
import { EventDispatcher, SphereGeometry, Mesh, MeshStandardMaterial, BackSide } from "three";
class GenericObject extends EventDispatcher{
constructor(engine, data){
@@ -9,6 +9,20 @@ class GenericObject extends EventDispatcher{
this.object = centerOrigin(this.source.scene)
if (!data.exclude){
const bckGeometry = new SphereGeometry(getBoundingBoxMaxLength(this.object.userData.bbox)/2,8,8)
const bckMesh = new Mesh(bckGeometry, new MeshStandardMaterial({
transparent: true,
opacity:1, color: 0xaaaaaa,
alphaMap: await engine.loadTexture('locked.webp', '/static/textures/'),
}))
this.object.add(bckMesh)
engine.motionQueue.add(
{ o: bckMesh, a:{
material: { opacity: k=>0.11 + 0.52*Math.sin(k*Math.PI)},
rotation: { y: k=>k*Math.PI*2},
scale: (k,s)=>s.setScalar(1+0.11*Math.sin(2*k*Math.PI))
}, r: true, t: 3 },
)
engine.clickable.add(this.object, async e=>{
this.object._active = !this.object._active;
if (engine.dashboard){
+10 -11
View File
@@ -1,18 +1,16 @@
<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>
<div v-if="modelValue.go">
<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" :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-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>
<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>
@@ -43,6 +41,7 @@ export default {
this.modelValue.count = 1000;
this.modelValue.w = 50;
this.modelValue.h = 50;
this.modelValue.exclude = true;
}
}
}
+20 -5
View File
@@ -1,4 +1,10 @@
<template>
<teleport to=".scene-designer .lines" v-if="active">
<OffsetLine v-for="(t, i) in modelValue.activationTriggers" :x1="vd.x1" :y1="vd.y1"
:x2="parent.data.items.find(i=>i.data.id == t)?.vd.x1"
:y2="parent.data.items.find(i=>i.data.id == t)?.vd.y1" :o1="52" :o2="52"
class="trigger" marker-start="url(#arrow)" ></OffsetLine>
</teleport>
<teleport to=".scene-designer .game-objects" v-if="active">
<g @mousedown="$emit('target', {target:vd, attrs:['x1', 'y1'], delta: true})" :class="{gameObject: true, selected}"
v-show="showInView">
@@ -18,14 +24,21 @@
</asset-selector>
<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.id" v-model="modelValue.id"></v-text-field>
<!-- <v-text-field density="compact" :label="l.id" v-model="modelValue.id"></v-text-field> -->
<v-number-input density="compact" label="Completion points" v-model="modelValue.points"></v-number-input>
</v-form>
<v-container v-if="selected && modelValue.type">
<component :is="modelValue.type" v-model="mv"></component>
</v-container>
<v-card title="Activation requirements" v-if="modelValue.type != 'CharacterObject'">
<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"
: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-card>
</v-card>
<v-container v-if="selected && modelValue.type">
<component :is="modelValue.type" v-model="mv"></component>
</v-container>
</template>
<script>
@@ -39,10 +52,11 @@ import MazeQuizGame from '../InteractiveObjects/MazeQuizGame/MazeQuizGame.vue';
import Particles from '../InteractiveObjects/Particles.vue';
import GenericObject from '../InteractiveObjects/GenericObject.vue';
import CharacterObject from '../InteractiveObjects/CharacterObject.vue';
import OffsetLine from './OffsetLine.vue';
export default {
emits:['target', 'preview'],
components: { SvgIcon, GenericObject, CharacterObject, VideoPlayer, PuzzleGame1, PuzzleGame2, MazeQuizGame, Particles, },
components: { SvgIcon, OffsetLine, GenericObject, CharacterObject, VideoPlayer, PuzzleGame1, PuzzleGame2, MazeQuizGame, Particles, },
data(){
return {
active: false
@@ -51,6 +65,7 @@ export default {
mounted(){
this.active = true;
this.modelValue.points ??= 10;
this.modelValue.activationScore ??= 0;
},
props:{
//context: Object,
@@ -0,0 +1,35 @@
<template>
<line :x1="ox1" :y1="oy1" :x2="ox2" :y2="oy2"></line>
</template>
<script>
export default {
props:{
x1: Number, y1: Number, x2: Number, y2: Number,
o1: Number, o2: Number
},
data(){
return {
ox1:0, ox2:0, oy1:0, oy2:0
}
},
mounted(){
this.calc();
this.$watch(
(vm) => (vm.x1, vm.y1, vm.x2, vm.y2, vm.o1, vm.o2, Date.now()),
this.calc
)
},
methods:{
calc: function(){
let dx = this.x2 - this.x1, dy = this.y2 - this.y1;
let a = Math.atan2(dy, dx);
let h = Math.sqrt(dx*dx + dy*dy);
this.ox1 = this.x1 + this.o1 * Math.cos(a);
this.oy1 = this.y1 + this.o1 * Math.sin(a);
this.ox2 = this.x1 + (h-this.o1) * Math.cos(a);
this.oy2 = this.y1 + (h-this.o1) * Math.sin(a);
}
}
}
</script>
@@ -19,7 +19,14 @@
<svg class="scene-designer" @resize="resize" :width="viewBox.w" :height="viewBox.h"
:viewBox="`${vb.x} ${vb.y} ${vb.w} ${vb.h}`" x="0" y="0" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<marker id="arrow" viewBox="0 0 10 10" refX="5" refY="5"
markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" />
</marker>
</defs>
<SvgRectangle v-model="selector" class="selector"></SvgRectangle>
<g class="lines"></g>
<g class="tasks"></g>
<g class="game-objects"></g>
<g class="scenes"></g>
+2 -2
View File
@@ -57,8 +57,8 @@ function autoScale(object, mk = 1) {
function centerOrigin(object){
let result = new Group();
let bb = getBoundingBox(object);
let position = getBoundingBoxCenterPoint(bb, object.position).negate();
result.userData.bbox = getBoundingBox(object);
let position = getBoundingBoxCenterPoint(result.userData.bbox, object.position).negate();
object.position.copy(position)
result.add(object);
return result;
+4 -1
View File
@@ -18,7 +18,10 @@ class MotionEngine {
if (mode == 'offset') {
target[key] = (initial[key] || 0) + value * k;
} else if (typeof (value) == 'function') {
target[key] = value(k);
let v = value(k, target[key]);
if (target[key] !== v){
target[key] = v;
}
} else {
target[key] = (initial[key] || 0) + (value - (initial[key] || 0)) * k;
}
+4
View File
@@ -77,6 +77,10 @@ video{
stroke: rgb(213, 226, 231);
stroke-width: calc( 2px * var(--svg-scale) );
}
line.trigger, marker#arrow path {
stroke: rgb(244, 215, 230);
fill: rgb(172, 105, 139);
}
g.selector {
line {
stroke-dasharray: 0 calc(8 * var(--svg-scale)) 0;