UNPKG

playcanvas

Version:

Open-source WebGL/WebGPU 3D engine for the web

1,055 lines (1,054 loc) 25.5 kB
import { Vec3 } from "../../../core/math/vec3.js"; import { BLEND_NORMAL, EMITTERSHAPE_BOX, LAYERID_DEPTH, LAYERID_WORLD, PARTICLEORIENTATION_SCREEN } from "../../../scene/constants.js"; import { Mesh } from "../../../scene/mesh.js"; import { ParticleEmitter } from "../../../scene/particle-system/particle-emitter.js"; import { Asset } from "../../asset/asset.js"; import { Component } from "../component.js"; const ASSET_PROPERTIES = ["colorMapAsset", "normalMapAsset", "meshAsset", "renderAsset"]; const _properties = [ "autoPlay", "numParticles", "lifetime", "rate", "rate2", "startAngle", "startAngle2", "loop", "preWarm", "lighting", "halfLambert", "intensity", "depthWrite", "noFog", "depthSoftening", "sort", "blendType", "stretch", "alignToMotion", "emitterShape", "emitterExtents", "emitterExtentsInner", "emitterRadius", "emitterRadiusInner", "initialVelocity", "wrap", "wrapBounds", "localSpace", "screenSpace", "colorMapAsset", "normalMapAsset", "mesh", "meshAsset", "renderAsset", "orientation", "particleNormal", "localVelocityGraph", "localVelocityGraph2", "velocityGraph", "velocityGraph2", "rotationSpeedGraph", "rotationSpeedGraph2", "radialSpeedGraph", "radialSpeedGraph2", "scaleGraph", "scaleGraph2", "colorGraph", "colorGraph2", "alphaGraph", "alphaGraph2", "colorMap", "normalMap", "animTilesX", "animTilesY", "animStartFrame", "animNumFrames", "animNumAnimations", "animIndex", "randomizeAnimIndex", "animSpeed", "animLoop", "layers" ]; let depthLayer; class ParticleSystemComponent extends Component { emitter = null; _requestedDepth = false; _drawOrder = 0; _paused = false; _evtLayersChanged = null; _evtLayerAdded = null; _evtLayerRemoved = null; _evtSetMeshes = null; _autoPlay = true; _numParticles = 1; _lifetime = 50; _rate = 1; _rate2 = null; _startAngle = 0; _startAngle2 = null; _loop = true; _preWarm = false; _lighting = false; _halfLambert = false; _intensity = 1; _depthWrite = false; _noFog = false; _depthSoftening = 0; _sort = 0; _blendType = BLEND_NORMAL; _stretch = 0; _alignToMotion = false; _emitterShape = EMITTERSHAPE_BOX; _emitterExtents = new Vec3(); _emitterExtentsInner = new Vec3(); _emitterRadius = 0; _emitterRadiusInner = 0; _initialVelocity = 0; _wrap = false; _wrapBounds = new Vec3(); _localSpace = false; _screenSpace = false; _colorMapAsset = null; _normalMapAsset = null; _mesh = null; _meshAsset = null; _renderAsset = null; _orientation = PARTICLEORIENTATION_SCREEN; _particleNormal = new Vec3(0, 1, 0); _localVelocityGraph = null; _localVelocityGraph2 = null; _velocityGraph = null; _velocityGraph2 = null; _rotationSpeedGraph = null; _rotationSpeedGraph2 = null; _radialSpeedGraph = null; _radialSpeedGraph2 = null; _scaleGraph = null; _scaleGraph2 = null; _colorGraph = null; _colorGraph2 = null; _alphaGraph = null; _alphaGraph2 = null; _colorMap = null; _normalMap = null; _animTilesX = 1; _animTilesY = 1; _animStartFrame = 0; _animNumFrames = 1; _animNumAnimations = 1; _animIndex = 0; _randomizeAnimIndex = false; _animSpeed = 1; _animLoop = true; _layers = [LAYERID_WORLD]; set autoPlay(arg) { this._autoPlay = arg; } get autoPlay() { return this._autoPlay; } set numParticles(arg) { this._setComplexProperty("numParticles", arg); } get numParticles() { return this._numParticles; } set lifetime(arg) { this._setComplexProperty("lifetime", arg); } get lifetime() { return this._lifetime; } set rate(arg) { this._setComplexProperty("rate", arg); } get rate() { return this._rate; } set rate2(arg) { this._setComplexProperty("rate2", arg); } get rate2() { return this._rate2; } set startAngle(arg) { this._setComplexProperty("startAngle", arg); } get startAngle() { return this._startAngle; } set startAngle2(arg) { this._setComplexProperty("startAngle2", arg); } get startAngle2() { return this._startAngle2; } set loop(arg) { this._loop = arg; if (this.emitter) { this.emitter.loop = arg; this.emitter.resetTime(arg ? void 0 : this.emitter.lifetime); this.emitter.resetMaterial(); } } get loop() { return this._loop; } set preWarm(arg) { this._setComplexProperty("preWarm", arg); } get preWarm() { return this._preWarm; } set lighting(arg) { this._setComplexProperty("lighting", arg); } get lighting() { return this._lighting; } set halfLambert(arg) { this._setComplexProperty("halfLambert", arg); } get halfLambert() { return this._halfLambert; } set intensity(arg) { this._setComplexProperty("intensity", arg); } get intensity() { return this._intensity; } set depthWrite(arg) { this._setComplexProperty("depthWrite", arg); } get depthWrite() { return this._depthWrite; } set noFog(arg) { this._setComplexProperty("noFog", arg); } get noFog() { return this._noFog; } set depthSoftening(arg) { const oldValue = this._depthSoftening; if (oldValue !== arg) { this._depthSoftening = arg; if (arg) { if (this.enabled && this.entity.enabled) this._requestDepth(); } else { if (this.enabled && this.entity.enabled) this._releaseDepth(); } if (this.emitter) { this.emitter.depthSoftening = arg; this.reset(); this.emitter.resetMaterial(); this.rebuild(); } } } get depthSoftening() { return this._depthSoftening; } set sort(arg) { this._setComplexProperty("sort", arg); } get sort() { return this._sort; } set blendType(arg) { this._blendType = arg; if (this.emitter) { this.emitter.blendType = arg; this.emitter.material.blendType = arg; this.emitter.resetMaterial(); this.rebuild(); } } get blendType() { return this._blendType; } set stretch(arg) { this._setComplexProperty("stretch", arg); } get stretch() { return this._stretch; } set alignToMotion(arg) { this._setComplexProperty("alignToMotion", arg); } get alignToMotion() { return this._alignToMotion; } set emitterShape(arg) { this._setComplexProperty("emitterShape", arg); } get emitterShape() { return this._emitterShape; } set emitterExtents(arg) { this._setSimpleProperty("emitterExtents", arg); } get emitterExtents() { return this._emitterExtents; } set emitterExtentsInner(arg) { this._setSimpleProperty("emitterExtentsInner", arg); } get emitterExtentsInner() { return this._emitterExtentsInner; } set emitterRadius(arg) { this._setSimpleProperty("emitterRadius", arg); } get emitterRadius() { return this._emitterRadius; } set emitterRadiusInner(arg) { this._setSimpleProperty("emitterRadiusInner", arg); } get emitterRadiusInner() { return this._emitterRadiusInner; } set initialVelocity(arg) { this._setSimpleProperty("initialVelocity", arg); } get initialVelocity() { return this._initialVelocity; } set wrap(arg) { this._setComplexProperty("wrap", arg); } get wrap() { return this._wrap; } set wrapBounds(arg) { this._setComplexProperty("wrapBounds", arg); } get wrapBounds() { return this._wrapBounds; } set localSpace(arg) { this._setComplexProperty("localSpace", arg); } get localSpace() { return this._localSpace; } set screenSpace(arg) { this._setComplexProperty("screenSpace", arg); } get screenSpace() { return this._screenSpace; } set colorMapAsset(arg) { const assets = this.system.app.assets; if (this._colorMapAsset) { const asset = assets.get(this._colorMapAsset); if (asset) { this._unbindColorMapAsset(asset); } } if (arg instanceof Asset) { arg = arg.id; } this._colorMapAsset = arg; if (arg) { const asset = assets.get(arg); if (asset) { this._bindColorMapAsset(asset); } else { assets.once(`add:${arg}`, (asset2) => { this._bindColorMapAsset(asset2); }); } } else { this.colorMap = null; } } get colorMapAsset() { return this._colorMapAsset; } set normalMapAsset(arg) { const assets = this.system.app.assets; if (this._normalMapAsset) { const asset = assets.get(this._normalMapAsset); if (asset) { this._unbindNormalMapAsset(asset); } } if (arg instanceof Asset) { arg = arg.id; } this._normalMapAsset = arg; if (arg) { const asset = assets.get(arg); if (asset) { this._bindNormalMapAsset(asset); } else { assets.once(`add:${arg}`, (asset2) => { this._bindNormalMapAsset(asset2); }); } } else { this.normalMap = null; } } get normalMapAsset() { return this._normalMapAsset; } set mesh(arg) { if (!arg || arg instanceof Asset || typeof arg === "number") { this.meshAsset = arg; } else { this._onMeshChanged(arg); } } get mesh() { return this._mesh; } set meshAsset(arg) { const assets = this.system.app.assets; if (this._meshAsset) { const asset = assets.get(this._meshAsset); if (asset) { this._unbindMeshAsset(asset); } } if (arg instanceof Asset) { arg = arg.id; } this._meshAsset = arg; if (arg) { const asset = assets.get(arg); if (asset) { this._bindMeshAsset(asset); } } else { this._onMeshChanged(null); } } get meshAsset() { return this._meshAsset; } set renderAsset(arg) { const assets = this.system.app.assets; if (this._renderAsset) { const asset = assets.get(this._renderAsset); if (asset) { this._unbindRenderAsset(asset); } } if (arg instanceof Asset) { arg = arg.id; } this._renderAsset = arg; if (arg) { const asset = assets.get(arg); if (asset) { this._bindRenderAsset(asset); } } else { this._onRenderChanged(null); } } get renderAsset() { return this._renderAsset; } set orientation(arg) { this._setComplexProperty("orientation", arg); } get orientation() { return this._orientation; } set particleNormal(arg) { this._setSimpleProperty("particleNormal", arg); } get particleNormal() { return this._particleNormal; } set localVelocityGraph(arg) { this._setGraphProperty("localVelocityGraph", arg); } get localVelocityGraph() { return this._localVelocityGraph; } set localVelocityGraph2(arg) { this._setGraphProperty("localVelocityGraph2", arg); } get localVelocityGraph2() { return this._localVelocityGraph2; } set velocityGraph(arg) { this._setGraphProperty("velocityGraph", arg); } get velocityGraph() { return this._velocityGraph; } set velocityGraph2(arg) { this._setGraphProperty("velocityGraph2", arg); } get velocityGraph2() { return this._velocityGraph2; } set rotationSpeedGraph(arg) { this._setGraphProperty("rotationSpeedGraph", arg); } get rotationSpeedGraph() { return this._rotationSpeedGraph; } set rotationSpeedGraph2(arg) { this._setGraphProperty("rotationSpeedGraph2", arg); } get rotationSpeedGraph2() { return this._rotationSpeedGraph2; } set radialSpeedGraph(arg) { this._setGraphProperty("radialSpeedGraph", arg); } get radialSpeedGraph() { return this._radialSpeedGraph; } set radialSpeedGraph2(arg) { this._setGraphProperty("radialSpeedGraph2", arg); } get radialSpeedGraph2() { return this._radialSpeedGraph2; } set scaleGraph(arg) { this._setGraphProperty("scaleGraph", arg); } get scaleGraph() { return this._scaleGraph; } set scaleGraph2(arg) { this._setGraphProperty("scaleGraph2", arg); } get scaleGraph2() { return this._scaleGraph2; } set colorGraph(arg) { this._setGraphProperty("colorGraph", arg); } get colorGraph() { return this._colorGraph; } set colorGraph2(arg) { this._setGraphProperty("colorGraph2", arg); } get colorGraph2() { return this._colorGraph2; } set alphaGraph(arg) { this._setGraphProperty("alphaGraph", arg); } get alphaGraph() { return this._alphaGraph; } set alphaGraph2(arg) { this._setGraphProperty("alphaGraph2", arg); } get alphaGraph2() { return this._alphaGraph2; } set colorMap(arg) { this._setComplexProperty("colorMap", arg); } get colorMap() { return this._colorMap; } set normalMap(arg) { this._setSimpleProperty("normalMap", arg); } get normalMap() { return this._normalMap; } set animTilesX(arg) { this._setComplexProperty("animTilesX", arg); } get animTilesX() { return this._animTilesX; } set animTilesY(arg) { this._setComplexProperty("animTilesY", arg); } get animTilesY() { return this._animTilesY; } set animStartFrame(arg) { this._setComplexProperty("animStartFrame", arg); } get animStartFrame() { return this._animStartFrame; } set animNumFrames(arg) { this._setComplexProperty("animNumFrames", arg); } get animNumFrames() { return this._animNumFrames; } set animNumAnimations(arg) { this._setComplexProperty("animNumAnimations", arg); } get animNumAnimations() { return this._animNumAnimations; } set animIndex(arg) { this._setComplexProperty("animIndex", arg); } get animIndex() { return this._animIndex; } set randomizeAnimIndex(arg) { this._setComplexProperty("randomizeAnimIndex", arg); } get randomizeAnimIndex() { return this._randomizeAnimIndex; } set animSpeed(arg) { this._setSimpleProperty("animSpeed", arg); } get animSpeed() { return this._animSpeed; } set animLoop(arg) { this._setComplexProperty("animLoop", arg); } get animLoop() { return this._animLoop; } set layers(arg) { const oldLayers = this._layers; this._layers = arg; if (!this.emitter) return; for (let i = 0; i < oldLayers.length; i++) { const layer = this.system.app.scene.layers.getLayerById(oldLayers[i]); if (!layer) continue; layer.removeMeshInstances([this.emitter.meshInstance]); } if (!this.enabled || !this.entity.enabled) return; for (let i = 0; i < arg.length; i++) { const layer = this.system.app.scene.layers.getLayerById(arg[i]); if (!layer) continue; layer.addMeshInstances([this.emitter.meshInstance]); } } get layers() { return this._layers; } set drawOrder(drawOrder) { this._drawOrder = drawOrder; if (this.emitter) { this.emitter.drawOrder = drawOrder; } } get drawOrder() { return this._drawOrder; } _setSimpleProperty(name, arg) { this[`_${name}`] = arg; if (this.emitter) { this.emitter[name] = arg; this.emitter.resetMaterial(); } } _setComplexProperty(name, arg) { this[`_${name}`] = arg; if (this.emitter) { this.emitter[name] = arg; this.emitter.resetMaterial(); this.rebuild(); this.reset(); } } _setGraphProperty(name, arg) { this[`_${name}`] = arg; if (this.emitter) { this.emitter[name] = arg; this.emitter.rebuildGraphs(); this.emitter.resetMaterial(); } } addMeshInstanceToLayers() { if (!this.emitter) return; for (let i = 0; i < this._layers.length; i++) { const layer = this.system.app.scene.layers.getLayerById(this._layers[i]); if (!layer) continue; layer.addMeshInstances([this.emitter.meshInstance]); this.emitter._layer = layer; } } removeMeshInstanceFromLayers() { if (!this.emitter) return; for (let i = 0; i < this._layers.length; i++) { const layer = this.system.app.scene.layers.getLayerById(this._layers[i]); if (!layer) continue; layer.removeMeshInstances([this.emitter.meshInstance]); } } onLayersChanged(oldComp, newComp) { this.addMeshInstanceToLayers(); oldComp.off("add", this.onLayerAdded, this); oldComp.off("remove", this.onLayerRemoved, this); newComp.on("add", this.onLayerAdded, this); newComp.on("remove", this.onLayerRemoved, this); } onLayerAdded(layer) { if (!this.emitter) return; const index = this._layers.indexOf(layer.id); if (index < 0) return; layer.addMeshInstances([this.emitter.meshInstance]); } onLayerRemoved(layer) { if (!this.emitter) return; const index = this._layers.indexOf(layer.id); if (index < 0) return; layer.removeMeshInstances([this.emitter.meshInstance]); } _bindColorMapAsset(asset) { asset.on("load", this._onColorMapAssetLoad, this); asset.on("unload", this._onColorMapAssetUnload, this); asset.on("remove", this._onColorMapAssetRemove, this); asset.on("change", this._onColorMapAssetChange, this); if (asset.resource) { this._onColorMapAssetLoad(asset); } else { if (!this.enabled || !this.entity.enabled) return; this.system.app.assets.load(asset); } } _unbindColorMapAsset(asset) { asset.off("load", this._onColorMapAssetLoad, this); asset.off("unload", this._onColorMapAssetUnload, this); asset.off("remove", this._onColorMapAssetRemove, this); asset.off("change", this._onColorMapAssetChange, this); } _onColorMapAssetLoad(asset) { this.colorMap = asset.resource; } _onColorMapAssetUnload(asset) { this.colorMap = null; } _onColorMapAssetRemove(asset) { this._onColorMapAssetUnload(asset); } _onColorMapAssetChange(asset) { } _bindNormalMapAsset(asset) { asset.on("load", this._onNormalMapAssetLoad, this); asset.on("unload", this._onNormalMapAssetUnload, this); asset.on("remove", this._onNormalMapAssetRemove, this); asset.on("change", this._onNormalMapAssetChange, this); if (asset.resource) { this._onNormalMapAssetLoad(asset); } else { if (!this.enabled || !this.entity.enabled) return; this.system.app.assets.load(asset); } } _unbindNormalMapAsset(asset) { asset.off("load", this._onNormalMapAssetLoad, this); asset.off("unload", this._onNormalMapAssetUnload, this); asset.off("remove", this._onNormalMapAssetRemove, this); asset.off("change", this._onNormalMapAssetChange, this); } _onNormalMapAssetLoad(asset) { this.normalMap = asset.resource; } _onNormalMapAssetUnload(asset) { this.normalMap = null; } _onNormalMapAssetRemove(asset) { this._onNormalMapAssetUnload(asset); } _onNormalMapAssetChange(asset) { } _bindMeshAsset(asset) { asset.on("load", this._onMeshAssetLoad, this); asset.on("unload", this._onMeshAssetUnload, this); asset.on("remove", this._onMeshAssetRemove, this); asset.on("change", this._onMeshAssetChange, this); if (asset.resource) { this._onMeshAssetLoad(asset); } else { if (!this.enabled || !this.entity.enabled) return; this.system.app.assets.load(asset); } } _unbindMeshAsset(asset) { asset.off("load", this._onMeshAssetLoad, this); asset.off("unload", this._onMeshAssetUnload, this); asset.off("remove", this._onMeshAssetRemove, this); asset.off("change", this._onMeshAssetChange, this); } _onMeshAssetLoad(asset) { this._onMeshChanged(asset.resource); } _onMeshAssetUnload(asset) { this.mesh = null; } _onMeshAssetRemove(asset) { this._onMeshAssetUnload(asset); } _onMeshAssetChange(asset) { } _onMeshChanged(mesh) { if (mesh && !(mesh instanceof Mesh)) { if (mesh.meshInstances[0]) { mesh = mesh.meshInstances[0].mesh; } else { mesh = null; } } this._mesh = mesh; if (this.emitter) { this.emitter.mesh = mesh; this.emitter.resetMaterial(); this.rebuild(); } } _bindRenderAsset(asset) { asset.on("load", this._onRenderAssetLoad, this); asset.on("unload", this._onRenderAssetUnload, this); asset.on("remove", this._onRenderAssetRemove, this); if (asset.resource) { this._onRenderAssetLoad(asset); } else { if (!this.enabled || !this.entity.enabled) return; this.system.app.assets.load(asset); } } _unbindRenderAsset(asset) { asset.off("load", this._onRenderAssetLoad, this); asset.off("unload", this._onRenderAssetUnload, this); asset.off("remove", this._onRenderAssetRemove, this); this._evtSetMeshes?.off(); this._evtSetMeshes = null; } _onRenderAssetLoad(asset) { this._onRenderChanged(asset.resource); } _onRenderAssetUnload(asset) { this._onRenderChanged(null); } _onRenderAssetRemove(asset) { this._onRenderAssetUnload(asset); } _onRenderChanged(render) { if (!render) { this._onMeshChanged(null); return; } this._evtSetMeshes?.off(); this._evtSetMeshes = render.on("set:meshes", this._onRenderSetMeshes, this); if (render.meshes) { this._onRenderSetMeshes(render.meshes); } } _onRenderSetMeshes(meshes) { this._onMeshChanged(meshes && meshes[0]); } _requestDepth() { if (this._requestedDepth) return; if (!depthLayer) depthLayer = this.system.app.scene.layers.getLayerById(LAYERID_DEPTH); if (depthLayer) { depthLayer.incrementCounter(); this._requestedDepth = true; } } _releaseDepth() { if (!this._requestedDepth) return; if (depthLayer) { depthLayer.decrementCounter(); this._requestedDepth = false; } } onEnable() { const scene = this.system.app.scene; const layers = scene.layers; for (let i = 0, len = ASSET_PROPERTIES.length; i < len; i++) { let asset = this[`_${ASSET_PROPERTIES[i]}`]; if (asset) { if (!(asset instanceof Asset)) { const id = parseInt(asset, 10); if (id >= 0) { asset = this.system.app.assets.get(asset); } else { continue; } } if (asset && !asset.resource) { this.system.app.assets.load(asset); } } } if (this.system.app.graphicsDevice.disableParticleSystem) { return; } if (!this.emitter) { this.emitter = new ParticleEmitter(this.system.app.graphicsDevice, { numParticles: this._numParticles, emitterExtents: this._emitterExtents, emitterExtentsInner: this._emitterExtentsInner, emitterRadius: this._emitterRadius, emitterRadiusInner: this._emitterRadiusInner, emitterShape: this._emitterShape, initialVelocity: this._initialVelocity, wrap: this._wrap, localSpace: this._localSpace, screenSpace: this._screenSpace, wrapBounds: this._wrapBounds, lifetime: this._lifetime, rate: this._rate, rate2: this._rate2, orientation: this._orientation, particleNormal: this._particleNormal, animTilesX: this._animTilesX, animTilesY: this._animTilesY, animStartFrame: this._animStartFrame, animNumFrames: this._animNumFrames, animNumAnimations: this._animNumAnimations, animIndex: this._animIndex, randomizeAnimIndex: this._randomizeAnimIndex, animSpeed: this._animSpeed, animLoop: this._animLoop, startAngle: this._startAngle, startAngle2: this._startAngle2, scaleGraph: this._scaleGraph, scaleGraph2: this._scaleGraph2, colorGraph: this._colorGraph, colorGraph2: this._colorGraph2, alphaGraph: this._alphaGraph, alphaGraph2: this._alphaGraph2, localVelocityGraph: this._localVelocityGraph, localVelocityGraph2: this._localVelocityGraph2, velocityGraph: this._velocityGraph, velocityGraph2: this._velocityGraph2, rotationSpeedGraph: this._rotationSpeedGraph, rotationSpeedGraph2: this._rotationSpeedGraph2, radialSpeedGraph: this._radialSpeedGraph, radialSpeedGraph2: this._radialSpeedGraph2, colorMap: this._colorMap, normalMap: this._normalMap, loop: this._loop, preWarm: this._preWarm, sort: this._sort, stretch: this._stretch, alignToMotion: this._alignToMotion, lighting: this._lighting, halfLambert: this._halfLambert, intensity: this._intensity, depthSoftening: this._depthSoftening, scene: this.system.app.scene, mesh: this._mesh, depthWrite: this._depthWrite, noFog: this._noFog, node: this.entity, blendType: this._blendType }); this.emitter.meshInstance.node = this.entity; this.emitter.drawOrder = this._drawOrder; if (!this._autoPlay) { this.pause(); this.emitter.meshInstance.visible = false; } } if (this.emitter.colorMap) { this.addMeshInstanceToLayers(); } this._evtLayersChanged = scene.on("set:layers", this.onLayersChanged, this); if (layers) { this._evtLayerAdded = layers.on("add", this.onLayerAdded, this); this._evtLayerRemoved = layers.on("remove", this.onLayerRemoved, this); } if (this.enabled && this.entity.enabled && this._depthSoftening) { this._requestDepth(); } } onDisable() { const scene = this.system.app.scene; const layers = scene.layers; this._evtLayersChanged?.off(); this._evtLayersChanged = null; if (layers) { this._evtLayerAdded?.off(); this._evtLayerAdded = null; this._evtLayerRemoved?.off(); this._evtLayerRemoved = null; } if (this.emitter) { this.removeMeshInstanceFromLayers(); if (this._depthSoftening) this._releaseDepth(); this.emitter.camera = null; } } onBeforeRemove() { if (this.enabled) { this.enabled = false; } if (this.emitter) { this.emitter.destroy(); this.emitter = null; } for (let i = 0; i < ASSET_PROPERTIES.length; i++) { const prop = ASSET_PROPERTIES[i]; if (this[`_${prop}`]) { this[prop] = null; } } this.off(); } reset() { if (this.emitter) { this.emitter.reset(); } } stop() { if (this.emitter) { this.emitter.loop = false; this.emitter.resetTime(this.emitter.lifetime); this.emitter.addTime(0, true); } } pause() { this._paused = true; } unpause() { this._paused = false; } play() { this._paused = false; if (this.emitter) { this.emitter.meshInstance.visible = true; this.emitter.loop = this._loop; this.emitter.resetTime(); } } isPlaying() { if (this._paused || !this.emitter) { return false; } if (this.emitter.loop) { return true; } return this.emitter.simTimeTotal <= this.emitter.endTime; } setInTools() { const { emitter } = this; if (emitter && !emitter.inTools) { emitter.inTools = true; this.rebuild(); } } rebuild() { const enabled = this.enabled; this.enabled = false; if (this.emitter) { this.emitter.rebuild(); } this.enabled = enabled; } } export { ParticleSystemComponent, _properties };