UNPKG

@urso/revolt-fx

Version:

Particle and Effect System for Pixi.js

270 lines 10.9 kB
/// <reference types="pixi.js" /> import { BaseEffect } from "./BaseEffect"; import { EffectSequenceComponentType } from "./EffectSequenceComponentType"; import { ParticleEmitter } from "./ParticleEmitter"; import { FXSignal } from "./util/FXSignal"; import { LinkedList, Node } from "./util/LinkedList"; import { Rnd } from "./util/Rnd"; export class EffectSequence extends BaseEffect { constructor(componentId) { super(componentId); this._list = []; this._elements = new LinkedList(); this.__on = { started: new FXSignal(), completed: new FXSignal(), exhausted: new FXSignal(), effectSpawned: new FXSignal(), triggerActivated: new FXSignal() }; } // ********************************************************************************************* // * Public * // ********************************************************************************************* init(container, delay = 0, autoStart = true, scaleMod = 1) { this.container = container; this._scaleMod = scaleMod; this._delay = delay * 1000; if (autoStart) this.start(); return this; } start() { if (this._active) return; this._startTime = Date.now() + (this.settings.delay ? this.settings.delay * 1000 : 0) + this._delay; this._index = 0; if (this._list.length == 0) { this._active = false; if (this.__on.exhausted.__hasCallback) { this.__on.exhausted.dispatch(this); } if (this.__on.completed.__hasCallback) { this.__on.completed.dispatch(this); } this.recycle(); return this; } this.exhausted = this.completed = false; this.setNextEffect(); this.__fx.effectSequenceCount++; this.__fx.__addActiveEffect(this); if (this.__on.started.__hasCallback) { this.__on.started.dispatch(this); } return this; } update(dt) { const t = Date.now(); if (t < this._startTime) return; this._time += dt; if (!this.exhausted && t >= this._effectStartTime) { const fx = this.__fx; const def = this._nextEffectSettings; let effect; let node; let container; switch (def.componentType) { case EffectSequenceComponentType.Sprite: effect = fx.__getSprite(def.componentId); container = fx.__containers[def.containerId] || this.container; container.addChild(effect); effect.blendMode = fx.__getBlendMode(def.blendMode); effect.tint = def.tint; effect.scale.set(Rnd.float(def.scaleMin, def.scaleMax) * Rnd.float(this.settings.scaleMin, this.settings.scaleMax) * this._scaleMod); effect.alpha = Rnd.float(def.alphaMin, def.alphaMax); effect.anchor.set(def.componentParams.anchorX, def.componentParams.anchorY); node = new Node({ component: effect, endTime: t + (def.duration) * 1000 }); this._elements.add(node); effect.x = this._x; effect.y = this._y; effect.rotation = this._rotation + Rnd.float(def.rotationMin, def.rotationMax); if (this.__on.effectSpawned.__hasCallback) { this.__on.effectSpawned.dispatch(EffectSequenceComponentType.Sprite, effect); } break; case EffectSequenceComponentType.MovieClip: effect = fx.__getMovieClip(def.componentId); if (def.componentParams.loop) { effect.animationSpeed = Rnd.float(def.componentParams.animationSpeedMin || 1, def.componentParams.animationSpeedMax || 1); effect.loop = def.componentParams.loop || false; } else { const speed = def.duration; } effect.anchor.set(def.componentParams.anchorX, def.componentParams.anchorY); effect.gotoAndPlay(0); container = fx.__containers[def.containerId] || this.container; container.addChild(effect); effect.blendMode = fx.__getBlendMode(def.blendMode); effect.tint = def.tint; effect.scale.set(Rnd.float(def.scaleMin, def.scaleMax) * Rnd.float(this.settings.scaleMin, this.settings.scaleMax) * this._scaleMod); effect.alpha = Rnd.float(def.alphaMin, def.alphaMax); node = new Node({ component: effect, endTime: t + (def.duration) * 1000 }); this._elements.add(node); effect.x = this._x; effect.y = this._y; effect.rotation = this._rotation + Rnd.float(def.rotationMin, def.rotationMax); if (this.__on.effectSpawned.__hasCallback) { this.__on.effectSpawned.dispatch(EffectSequenceComponentType.MovieClip, effect); } break; case EffectSequenceComponentType.Emitter: effect = fx.getParticleEmitterById(def.componentId); container = fx.__containers[def.containerId] || this.container; effect.init(container, true, Rnd.float(def.scaleMin, def.scaleMax) * Rnd.float(this.settings.scaleMin, this.settings.scaleMax) * this._scaleMod); node = new Node({ component: effect, endTime: effect.endTime }); this._elements.add(node); effect.x = this._x; effect.y = this._y; effect.rotation = this._rotation + effect.settings.rotation; if (this.__on.effectSpawned.__hasCallback) { this.__on.effectSpawned.dispatch(EffectSequenceComponentType.Emitter, effect); } break; case EffectSequenceComponentType.Trigger: if (this.__on.triggerActivated.__hasCallback) { this.__on.triggerActivated.dispatch(def.triggerValue); } break; } if (this._index == this._list.length) { this.exhausted = true; if (this.__on.exhausted.__hasCallback) { this.__on.exhausted.dispatch(this); } } else { this.setNextEffect(); } } const list = this._elements; let node = list.first; while (node) { node.update(dt); if (t > node.data.endTime) { const component = node.data.component; if (component instanceof ParticleEmitter) { if (component.completed) { list.remove(node); } } else { list.remove(node); component.recycle(); } } node = node.next; } if (this.exhausted && list.length == 0) { this._active = false; this.completed = true; if (this.__on.completed.__hasCallback) { this.__on.completed.dispatch(this); } this.recycle(); } } stop() { this.recycle(); } recycle() { if (this.__recycled) return; const list = this._elements; let node = list.first; let next; while (node) { next = node.next; node.data.component.recycle(); node = next; } const on = this.__on; if (on.completed.__hasCallback) on.completed.removeAll(); if (on.started.__hasCallback) on.started.removeAll(); if (on.exhausted.__hasCallback) on.exhausted.removeAll(); if (on.effectSpawned.__hasCallback) on.effectSpawned.removeAll(); if (on.triggerActivated.__hasCallback) on.triggerActivated.removeAll(); list.clear(); this.__recycled = true; this._x = this._y = this._rotation = 0; this.__fx.effectSequenceCount--; this.__fx.__recycleEffectSequence(this); } dispose() { this._elements.clear(); this.__fx = undefined; const on = this.__on; on.completed = on.started = on.exhausted = on.effectSpawned = on.triggerActivated = undefined; } set rotation(value) { this._rotation = value; const list = this._elements; let node = list.first; let next; while (node) { next = node.next; node.data.rotation = value; node = next; } } get x() { return this._x; } set x(value) { this._x = value; const list = this._elements; let node = list.first; let next; while (node) { next = node.next; node.data.x = value; node = next; } } get y() { return this._y; } set y(value) { this._y = value; const list = this._elements; let node = list.first; let next; while (node) { next = node.next; node.data.y = value; node = next; } } get rotation() { return this._rotation; } get on() { return this.__on; } // ********************************************************************************************* // * Private * // ********************************************************************************************* setNextEffect() { if (this.exhausted) return; const def = this._nextEffectSettings = this._list[this._index++]; this._effectStartTime = this._startTime + def.delay * 1000; } // ********************************************************************************************* // * Internal * // ********************************************************************************************* __applySettings(value) { this.settings = value; this.name = value.name; this._list = value.effects.slice(); this.__recycled = false; } } //# sourceMappingURL=EffectSequence.js.map