Hi I am creating an AR in Niantic Studio.
When an entity does ecs.physics.COLLISION_END_EVENT, I am setting the ParticleEmitter.
but I get an error (although it looks and works fine).
What causes this error? Could you help me?
I have set ParticleEmitter as follows:
ecs.ParticleEmitter.set(world, eid, {
stopped: false,
emitterLife: 1.2,
particlesPerShot: 1,
emitDelay: 0,
minimumLifespan: 0.01,
maximumLifespan: 0.2,
mass: 1,
gravity: 0.01,
scale: 0.0005,
spawnAreaType: 'box',
spawnAreaWidth: 0.1,
spawnAreaHeight: 0.1,
spawnAreaDepth: 0.1,
resourceType: 'model',
resourceUrl: './assets/particle.glb',
blendingMode: 'normal',
animateColor: true,
colorStart: '#E7C94D',
colorEnd: '#FFFFFF',
randomDrift: true,
randomDriftRange: 0.1,
collisions: false,
})
Errors are as follows.
▼ Unhandled promise rejection: SyntaxError: Unexpected token '<', "<?xml vers"... is not valid JSON
at GLTFLoader.parse runtime.js
at (anonymous) runtime.js
at GLTFLoader.parseAsync runtime.js
at (anonymous) runtime.js
SyntaxError: Unexpected token '<', "<?xml vers"... is not valid JSON
I checked particle.glb with the gltf validator and it seems to be error free.
https://github.khronos.org/glTF-Validator/
{
"uri": "particle.glb",
"mimeType": "model/gltf-binary",
"validatorVersion": "2.0.0-dev.3.10",
"validatedAt": "2025-01-20T06:46:32.049Z",
"issues": {
"numErrors": 0,
"numWarnings": 0,
"numInfos": 0,
"numHints": 0,
"messages": [],
"truncated": false
},
"info": {
"version": "2.0",
"generator": "Khronos glTF Blender I/O v4.1.62",
"resources": [
{
"pointer": "/buffers/0",
"mimeType": "application/gltf-buffer",
"storage": "glb",
"byteLength": 168
}
],
"animationCount": 0,
"materialCount": 0,
"hasMorphTargets": false,
"hasSkins": false,
"hasTextures": false,
"hasDefaultScene": true,
"drawCallCount": 1,
"totalVertexCount": 8,
"totalTriangleCount": 12,
"maxUVs": 0,
"maxInfluences": 0,
"maxAttributes": 1
}
}
Below is the full text of the relevant code.
// This is a component file. You can use this file to define a custom component for your project.
// This component will appear as a custom component in the editor.
import * as ecs from '@8thwall/ecs' // This is how you access the ecs library.
let customUi
let originalBox
let handleCollision
const {BoxGeometry, Material, Position, Quaternion, Scale, Shadow, ScaleAnimation, Audio} = ecs
const block = ecs.registerComponent({
name: 'block',
schema: {
customUi: ecs.eid,
originalBox: ecs.eid,
},
schemaDefaults: {
},
data: {
// Add data that cannot be configured outside of the component.
},
add: (world, component) => {
const {eid} = component
customUi = component.schema.customUi
originalBox = component.schema.originalBox
const componentsForRemove = [
Position, Quaternion, Scale, Shadow, BoxGeometry, Material,
ecs.CustomPropertyAnimation, ecs.CustomVec3Animation, ecs.FollowAnimation,
ecs.LookAtAnimation, ecs.GltfModel, ecs.Collider, ecs.ParticleEmitter, ecs.Audio,
]
const removeComponents = (world_, targetEid) => {
componentsForRemove.forEach((component_) => {
if (targetEid !== originalBox) {
if (component_.has(world_, targetEid)) {
component_.remove(world_, targetEid)
}
}
})
}
handleCollision = (e) => {
ecs.Hidden.set(world, eid, {})
ecs.ParticleEmitter.set(world, eid, {
stopped: false,
emitterLife: 1.2,
particlesPerShot: 1,
emitDelay: 0,
minimumLifespan: 0.01,
maximumLifespan: 0.2,
mass: 1,
gravity: 0.01,
scale: 0.0005,
spawnAreaType: 'box',
spawnAreaWidth: 0.1,
spawnAreaHeight: 0.1,
spawnAreaDepth: 0.1,
resourceType: 'model',
resourceUrl: './assets/particle.glb',
blendingMode: 'normal',
animateColor: true,
colorStart: '#E7C94D',
colorEnd: '#FFFFFF',
randomDrift: true,
randomDriftRange: 0.1,
collisions: false,
})
// if (ecs.Audio.has(world, eid)) {
// const audio = ecs.Audio.cursor(world, eid)
// audio.paused = false
// }
// ecs.Audio.mutate(world, eid, (cursor) => {
// cursor.paused = false
// })
if (ecs.Collider.has(world, eid)) {
ecs.Collider.remove(world, eid)
}
const remainingQuery = ecs.defineQuery([block])
const remaining = remainingQuery(world)
if (remaining.length === 2) {
world.events.dispatch(customUi, 'clear')
}
setTimeout(() => {
const remaining_ = remainingQuery(world)
if (remaining_.length === 1) {
world.events.dispatch(customUi, 'clear')
}
}, 1000)
setTimeout(() => {
world.deleteEntity(eid)
const remaining_ = remainingQuery(world)
if (remaining_.length === 1) {
world.events.dispatch(customUi, 'clear')
}
}, 5000)
}
// This listener logs a message whenever the entity collides with another entity.
world.events.addListener(eid, ecs.physics.COLLISION_END_EVENT, handleCollision)
},
tick: (world, component) => {
// Runs every frame.
},
remove: (world, component) => {
},
})
export {block, handleCollision}