スプライトの形に添ったパーティクルエミッタを作る②:random出力
前回の処理では辺からの出力しかできなかったので、今回はスプライトの範囲からパーティクルを出力する方法を探ってみます。
getRandomPointを持つクラスを作る
こちらのサンプルを見るとgetRandomPointが実装されているオブジェクトならなんでもエミッタゾーンとして設定できるようなので、getRandomPointを持つクラスを作ります。
export class EmitterPoints { public points: Phaser.Math.Vector2[] = []; public pointsCopy: Phaser.Math.Vector2[] = []; public vec: Phaser.Geom.Point; constructor(p:Phaser.Math.Vector2[]) { this.points = p; for (let i = 0; i < this.points.length; i++) { this.pointsCopy.push( new Phaser.Math.Vector2(0,0)); } this.vec= new Phaser.Geom.Point() } public getRandomPoint() { let p = this.pointsCopy[Math.floor(Phaser.Math.Between(0, this.points.length - 1))] this.vec.setTo(p.x,p.y) return this.vec; } }
しかし、こちらを実行してみてもうまく出力されませんでした。
サンプルと同じ形の実装のためにGetPixelを改造します。
public GetPixel(x: number, y: number, rotate: number, key: string) { if (this.vPoints[key] !== undefined) { let source = this.textures.get(key).getSourceImage() let points = this.vPoints[key] for (let i = 0; i < points.points.length; i++) { points.pointsCopy[i].set(((points.points[i].x - source.width / 2) * Math.cos(rotate) - (points.points[i].y - source.height / 2) * Math.sin(rotate)) , ((points.points[i].y - source.height / 2) * Math.cos(rotate) + (points.points[i].x - source.width / 2) * Math.sin(rotate)) ) } let r ={ getRandomPoint: function (vec) { let p = points.getRandomPoint() vec.x = p.x ; vec.y = p.y ; return vec; } }; this.emitter.setEmitZone({ source: r, type: 'random', quantity: 50 }); this.emitter.explode(3000,x,y) } else { let vp: Phaser.Math.Vector2[] =[]; let source = this.textures.get(key).getSourceImage() this.graphicsSub.clear(); for (let i = 0; i < source.height; i++) { for (let j = 0; j < source.width; j++) { let pixel = this.textures.getPixel(j, i, key, 0) if (pixel.alpha > 0) { vp.push(new Phaser.Math.Vector2( j,i)) let color = new Phaser.Display.Color(); color.setTo(0, 0, 0) let point = this.point.clone(); point.set(x + ((j - source.width / 2) * Math.cos(rotate) - (i - source.height / 2) * Math.sin(rotate)), y + ((i - source.height / 2) * Math.cos(rotate) + (j - source.width / 2) * Math.sin(rotate)), 1.5) let randompoint = this.point.clone() randompoint.x = Phaser.Math.Between(x - source.width / 2, x + source.width / 2) randompoint.y = Phaser.Math.Between(y - source.height / 2, y + source.height / 2) this.tweens.add({ targets: point, x: Phaser.Math.Between(0, this.sys.canvas.width), y: Phaser.Math.Between(0, this.sys.canvas.height), z: 0, ease: 'Power1', duration: 150 * Phaser.Math.Distance.Between(point.x, point.y, randompoint.x, randompoint.y), onComplete: () => { this.geomPoints.splice(this.geomPoints.indexOf(point), 1) }, }); this.geomPoints.push(point) } } } this.vPoints[key]=new EmitterPoints(vp) }
一度作成したエミッタの座標を配列に入れておくようにしました。
実行結果がこちらです。
先日実装したエフェクトはピクセルの一つ一つにtweenを設定していたのでパフォーマンスに問題がありましたが、こちらはparticleで実装しているので動作が早いです。