add collisionTypes

This commit is contained in:
2026-04-03 13:47:30 +03:00
parent 031bca9613
commit f9a249adb7
8 changed files with 58 additions and 27 deletions
@@ -8,7 +8,8 @@
<v-textarea :label="l.description" v-model="modelValue.description" class="mt-3"></v-textarea> <v-textarea :label="l.description" v-model="modelValue.description" class="mt-3"></v-textarea>
<v-checkbox density="compact" v-model="modelValue.hud" hide-details :label="l.viewInHUD"></v-checkbox> <v-checkbox density="compact" v-model="modelValue.hud" hide-details :label="l.viewInHUD"></v-checkbox>
<v-checkbox density="compact" v-model="modelValue.exclude" hide-details :label="l.disableInteractions"></v-checkbox> <v-checkbox density="compact" v-model="modelValue.exclude" hide-details :label="l.disableInteractions"></v-checkbox>
<v-checkbox density="compact" v-model="modelValue.noPhysics" hide-details :label="l.disableCollisions"></v-checkbox> <v-select :label="l.collisionType" v-model="modelValue.collisionType" density="compact" hide-details
:items="collisionTypes"></v-select>
<v-img :src="`/asset/thumb/${modelValue.go}.webp`" /> <v-img :src="`/asset/thumb/${modelValue.go}.webp`" />
<div class="text-caption text-center">{{ modelValue.title }}</div> <div class="text-caption text-center">{{ modelValue.title }}</div>
</div> </div>
@@ -19,11 +20,13 @@
export default { export default {
data(){ data(){
return { return {
active: false active: false,
collisionTypes: []
} }
}, },
mounted(){ mounted(){
this.active = true; this.active = true;
this.collisionTypes = Object.keys(this.l.collisionTypes).map(t=>({title: this.l.collisionTypes[t], value: t}))
}, },
props:{ props:{
modelValue: Object modelValue: Object
@@ -42,7 +42,6 @@ class MazeQuizGame extends EventManager {
constructor(engine, data) { constructor(engine, data) {
super(); super();
this.data = data; this.data = data;
data.noPhysics = true;
this.params = { ...params, mazeFile: data.style || 'quiz-s2.gltf', io: this } this.params = { ...params, mazeFile: data.style || 'quiz-s2.gltf', io: this }
@@ -10,7 +10,6 @@ import * as BufferGeometryUtils from 'three/addons/utils/BufferGeometryUtils.js'
class Particles { class Particles {
constructor(engine, data) { constructor(engine, data) {
data.noPhysics = true;
const { x, y, count, w, h } = data; const { x, y, count, w, h } = data;
let positions = Particles.positions(count, w, h); let positions = Particles.positions(count, w, h);
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
+1 -1
View File
@@ -258,7 +258,7 @@ class GameEngine extends EventManager{
event.preventDefault(); event.preventDefault();
if (this.hero){ if (this.hero){
if (!this.pointerControls.isLocked){ if (!this.pointerControls.isLocked){
this.hero.cameraZ += event.deltaY / 100; this.hero.cameraZ += event.deltaY * 0.005;
} }
}else{ }else{
this.camera.zoom -= event.deltaY / (1000 / this.camera.zoom); this.camera.zoom -= event.deltaY / (1000 / this.camera.zoom);
+4 -8
View File
@@ -52,12 +52,7 @@ class GameManager{
let env = await engine.load(scene.data.$scene.asset.name); let env = await engine.load(scene.data.$scene.asset.name);
this.setObjectAttributes(sceneObjects, scene.data, env.scene, env, null); this.setObjectAttributes(sceneObjects, scene.data, env.scene, env, null);
if (engine.opts.mode != 'GameDesigner'){ if (engine.opts.mode != 'GameDesigner'){
env.scene.traverse(o=>{ engine.physics.apply(env.scene)
if (o.name.startsWith('land') || o.name == 'Sphere'){
//this.debug('Fixing ground. TODO!!!')
engine.physics.add(o, 'fixed', true, undefined, 'mesh', { root: env.scene})
}
})
} }
engine.activeObjects.add(env.scene); engine.activeObjects.add(env.scene);
} }
@@ -86,13 +81,14 @@ class GameManager{
if (io.source?.animations?.length){ if (io.source?.animations?.length){
engine.playAnimation(engine.scene, io.source.animations[0]); engine.playAnimation(engine.scene, io.source.animations[0]);
} }
if (i.data.collisionType == 'basic'){
if (!i.data.noPhysics){
let bb = engine.meshUtils.getBoundingBox(io.object); let bb = engine.meshUtils.getBoundingBox(io.object);
let bbs = engine.meshUtils.getBoundingBoxSize(bb); let bbs = engine.meshUtils.getBoundingBoxSize(bb);
engine.physics.add(io.object, 'fixed', false, undefined, 'capsule', { engine.physics.add(io.object, 'fixed', false, undefined, 'capsule', {
radius: Math.max(bbs.x, bbs.z)/2, halfHeight: bbs.y/2 radius: Math.max(bbs.x, bbs.z)/2, halfHeight: bbs.y/2
}) })
}else if (i.data.collisionType == 'objectDefinied'){
engine.physics.apply(io.object)
} }
} }
io.addEventListener('finish', ()=>{ io.addEventListener('finish', ()=>{
+15 -10
View File
@@ -13,29 +13,29 @@ class Hero{
} }
set cameraZ(v){ set cameraZ(v){
this.#cameraZ = Math.min(Math.max(v, 1), 12); this.#cameraZ = Math.min(Math.max(v, this.cameraZMin), this.cameraZMax);
if (this.#cameraZ == 1 && !this.fpv){ if (this.#cameraZ == this.cameraZMin && !this.fpv){
if (this.engine.renderer.xr.isPresenting){ if (this.engine.renderer.xr.isPresenting){
this.#cameraZ = 0; this.#cameraZ = 0;
this.fpv = true; this.fpv = true;
this.cameraY = this.size.y*0.9; this.cameraY = this.cameraYBase;
this.camera.rotation.set(0,0,0); this.camera.rotation.set(0,0,0);
}else{ }else{
this.engine.pointerControls.lock(true).then(()=>{ this.engine.pointerControls.lock(true).then(()=>{
this.#cameraZ = 0; this.#cameraZ = 0;
this.fpv = true; this.fpv = true;
this.cameraY = this.size.y*0.9; this.cameraY = this.cameraYBase;
this.engine.pointerControls.once('unlock', ()=>{ this.engine.pointerControls.once('unlock', ()=>{
this.fpv = false; this.fpv = false;
this.cameraY = this.size.y*1.5; this.cameraY = this.cameraYBase * 1.5;
}) })
}).catch(err=>{ }).catch(err=>{
console.log(err); console.log(err);
}) })
} }
}else if(this.#cameraZ > 1 && this.fpv){ }else if(this.#cameraZ > this.cameraZMin && this.fpv){
this.fpv = false; this.fpv = false;
this.cameraY = this.size.y*1.5; this.cameraY = this.cameraYBase * 1.5;
} }
//this.engine.dashboard.updateText(this.#cameraZ); //this.engine.dashboard.updateText(this.#cameraZ);
} }
@@ -67,7 +67,12 @@ class Hero{
// let center = getBoundingBoxCenterPoint(bb, this.model.userData.object.position) // let center = getBoundingBoxCenterPoint(bb, this.model.userData.object.position)
let bb = engine.meshUtils.getBoundingBox(io.object); let bb = engine.meshUtils.getBoundingBox(io.object);
this.size = engine.meshUtils.getBoundingBoxSize(bb); this.size = engine.meshUtils.getBoundingBoxSize(bb);
console.log('Hero size is', this.size); //console.log('Hero size is', this.size);
this.cameraYBase = this.size.y / this.engine.scale;
this.cameraZMin = 1 / this.engine.scale;
this.cameraZMax = 12 / this.engine.scale;
this.#cameraZ = this.cameraZDefault = 4 / this.engine.scale;
// let center = getBoundingBoxCenterPoint(bb, io.object.position) // let center = getBoundingBoxCenterPoint(bb, io.object.position)
// console.log('hero', size, center, size.y - 2*this.characterGapOffset) // console.log('hero', size, center, size.y - 2*this.characterGapOffset)
@@ -97,7 +102,7 @@ class Hero{
this.orbitControl = this.engine.orbitControls this.orbitControl = this.engine.orbitControls
//this.camera = this.engine.camera; //this.camera = this.engine.camera;
this.camera = this.engine.cameraWorld; this.camera = this.engine.cameraWorld;
this.cameraY = this.size.y * 1.5; this.cameraY = this.cameraYBase * 1.5;
this.direction = this.model.rotation.y; this.direction = this.model.rotation.y;
//this.directionVelocity = 0; //this.directionVelocity = 0;
@@ -150,7 +155,7 @@ class Hero{
} }
if (!this.fpv && !this.model.visible){ if (!this.fpv && !this.model.visible){
this.model.visible = true; this.model.visible = true;
this.#cameraZ = 4 this.#cameraZ = this.cameraZDefault;
this.engine.camera.fov = 45; this.engine.camera.fov = 45;
this.engine.camera.updateProjectionMatrix(); this.engine.camera.updateProjectionMatrix();
} }
+19 -2
View File
@@ -32,7 +32,7 @@ class Physics{
add = (mesh, rigidBodyType, autoAnimate = true, postPhysicsFn, colliderType, colliderSettings = {}) => { add = (mesh, rigidBodyType, autoAnimate = true, postPhysicsFn, colliderType, colliderSettings = {}) => {
const rigidBodyDesc = RAPIER.RigidBodyDesc[rigidBodyType]() const rigidBodyDesc = RAPIER.RigidBodyDesc[rigidBodyType]()
let position, quaternion; let position, quaternion, scale = new Vector3(1,1,1);
// if (colliderSettings.root){ // if (colliderSettings.root){
// // mesh.getWorldPosition(position = new Vector3()); // // mesh.getWorldPosition(position = new Vector3());
// // mesh.getWorldQuaternion(quaternion = new Quaternion()); // // mesh.getWorldQuaternion(quaternion = new Quaternion());
@@ -42,6 +42,15 @@ class Physics{
position = mesh.position; position = mesh.position;
quaternion = mesh.quaternion; quaternion = mesh.quaternion;
//} //}
if (colliderSettings.root){
let p = mesh;
while (p != colliderSettings.root.parent) {
scale.multiply(p.scale);
p = p.parent;
}
}
rigidBodyDesc.setTranslation(position.x, position.y, position.z) rigidBodyDesc.setTranslation(position.x, position.y, position.z)
quaternion && rigidBodyDesc.setRotation(quaternion) quaternion && rigidBodyDesc.setRotation(quaternion)
@@ -76,7 +85,7 @@ class Physics{
const position = mesh.geometry.getAttribute( 'position' ); const position = mesh.geometry.getAttribute( 'position' );
for ( let i = 0; i < position.count; i ++ ) { for ( let i = 0; i < position.count; i ++ ) {
vertex.fromBufferAttribute( position, i ); vertex.fromBufferAttribute( position, i );
vertices.push( vertex.x, vertex.y, vertex.z ); vertices.push( vertex.x * scale.x, vertex.y * scale.x, vertex.z * scale.x );
} }
// if the buffer is non-indexed, generate an index buffer // if the buffer is non-indexed, generate an index buffer
@@ -111,6 +120,14 @@ class Physics{
return physicsObject return physicsObject
} }
apply(object){
object.traverse(o=>{
if (o.name.startsWith('land') || o.name.endsWith('-physics')){
this.add(o, 'fixed', true, undefined, 'mesh', { root: object})
}
})
}
clear(){ clear(){
this.physicsObjects.forEach(po=>{ this.physicsObjects.forEach(po=>{
po.characterController && this.world.removeCharacterController(po.characterController) po.characterController && this.world.removeCharacterController(po.characterController)
+14 -2
View File
@@ -48,7 +48,13 @@ const lang = {
minActivationScore: 'Minimum level score for activation', minActivationScore: 'Minimum level score for activation',
viewInHUD: 'Observe in head-up display', viewInHUD: 'Observe in head-up display',
disableInteractions: 'Disable interactions', disableInteractions: 'Disable interactions',
disableCollisions: 'Disable collisions', collisionType: 'Collision type',
collisionTypes: {
no: 'No collisions',
basic: 'Basic (sphere around object)',
objectDefinied: 'Defined in object',
advanced: 'Complex (not implemented)'
},
dimensions: 'Dimensions', dimensions: 'Dimensions',
elementsCount: 'Number of elements', elementsCount: 'Number of elements',
particleWidth: 'Particle width', particleWidth: 'Particle width',
@@ -204,7 +210,13 @@ const lang = {
minActivationScore: 'Минимален брой точки за активиране', minActivationScore: 'Минимален брой точки за активиране',
viewInHUD: 'Показване в HUD (head-up display)', viewInHUD: 'Показване в HUD (head-up display)',
disableInteractions: 'Без взаимодействия', disableInteractions: 'Без взаимодействия',
disableCollisions: 'Без колизии', collisionType: 'Тип колизии',
collisionTypes: {
no: 'Без',
basic: 'Базови (сфера около обекта)',
objectDefinied: 'От дефиницията на обекта',
advanced: 'С голяма точност (not implemented)'
},
dimensions: 'Размери', dimensions: 'Размери',
elementsCount: 'Брой елементи', elementsCount: 'Брой елементи',
particleWidth: 'Ширина на частиците', particleWidth: 'Ширина на частиците',