* Update the Particle * This is automatically called by the game manager game * @ignore * @param dt - time since the last update in milliseconds
(dt: number)
| 148 | * @param dt - time since the last update in milliseconds |
| 149 | */ |
| 150 | override update(dt: number) { |
| 151 | // move things forward independent of the current frame rate |
| 152 | const skew = dt * this._deltaInv; |
| 153 | |
| 154 | // Decrease particle life |
| 155 | this.life = this.life > dt ? this.life - dt : 0; |
| 156 | |
| 157 | if (this.alive && this.life <= 0) { |
| 158 | const parent = this.ancestor as Container; |
| 159 | // use true for keepalive since we recycle the instance directly here after |
| 160 | parent.removeChild(this, true); |
| 161 | particlePool.release(this); |
| 162 | this.alive = false; |
| 163 | return false; |
| 164 | } |
| 165 | |
| 166 | // Calculate the particle Age Ratio |
| 167 | const ageRatio = this.life / this.startLife; |
| 168 | |
| 169 | // Resize the particle as particle Age Ratio |
| 170 | let scale = this.startScale; |
| 171 | if (this.startScale > this.endScale) { |
| 172 | scale *= ageRatio; |
| 173 | scale = scale < this.endScale ? this.endScale : scale; |
| 174 | } else if (this.startScale < this.endScale) { |
| 175 | scale /= ageRatio; |
| 176 | scale = scale > this.endScale ? this.endScale : scale; |
| 177 | } |
| 178 | |
| 179 | // Set the particle opacity as Age Ratio |
| 180 | this.alpha = ageRatio; |
| 181 | |
| 182 | // Adjust the particle velocity |
| 183 | this.vel.x += this.wind * skew; |
| 184 | this.vel.y += this.gravity * skew; |
| 185 | |
| 186 | // If necessary update the rotation of particle in accordance the particle trajectory |
| 187 | const angle = this.followTrajectory |
| 188 | ? Math.atan2(this.vel.y, this.vel.x) |
| 189 | : this._angle; |
| 190 | |
| 191 | this.pos.x += this.vel.x * skew; |
| 192 | this.pos.y += this.vel.y * skew; |
| 193 | |
| 194 | // Update particle transform — closed-form of the 4-step builder |
| 195 | // ScaleAndTranslate · T(half) · R(θ) · T(−half) |
| 196 | // folded into a single setTransform() to skip 3 matrix multiplies per |
| 197 | // particle per frame. See `closed-form equivalence` tests in |
| 198 | // tests/emitter.spec.js for derivation + regression coverage. |
| 199 | const halfW = this._halfW; |
| 200 | const halfH = this._halfH; |
| 201 | const cos = Math.cos(angle); |
| 202 | const sin = Math.sin(angle); |
| 203 | const sCos = scale * cos; |
| 204 | const sSin = scale * sin; |
| 205 | this.currentTransform.setTransform( |
| 206 | sCos, |
| 207 | sSin, |
nothing calls this directly
no test coverage detected