スプライトの形に添ったパーティクルエミッタを作る②: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)
    }

一度作成したエミッタの座標を配列に入れておくようにしました。
実行結果がこちらです。 f:id:Phaser_3:20190129180915g:plain 先日実装したエフェクトはピクセルの一つ一つにtweenを設定していたのでパフォーマンスに問題がありましたが、こちらはparticleで実装しているので動作が早いです。