Phaser3:物理ボディからエフェクトを作る②

前回に引き続きエフェクトを作ってみます。

ピクセル群の位置を調節する

前回の記事ではスプライト左上から中心(origin)までの距離分ピクセルがずれてしまっていたので、ずれを加味した座標を計算します。

let point = Phaser.Geom.Point.Clone(this.point)
point.setTo(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)))
         

さらにピクセルにtweenを設定します。

this.tweens.add({
    targets: point,
    x: Phaser.Math.Between(0,this.sys.canvas.width),
    y: Phaser.Math.Between(0, this.sys.canvas.height),
    ease: 'Power1',
    duration: 300,
    onComplete: () => { this.geomPoints.splice(this.geomPoints.indexOf(point), 1) },
});

実行結果がこちらです。 f:id:Phaser_3:20190125133406p:plain f:id:Phaser_3:20190125133424g:plain 墨をばらまいたようなエフェクトができました。
GraphicsSubをclearしていないので軌跡が残ってしまっているようです。
これはこれで面白いのですが求めているものとは違う感じがするのでupdateでclearを行うようにし、飛散する範囲も狭めました。
さらにTweenも見直し、ポイントを縮小して飛沫の減衰を表現したいのでFillRectShapeを用いるようにします。
pointはvector3で定義しなおし、zの値をポイントのスケールとして扱うようにしました。

}

create() {
    this.graphicsSub = this.add.graphics();
    this.point = new Phaser.Math.Vector3(0, 0,0);
    this.matter.world.setBounds();

    this.cameras.main.setBackgroundColor(0xffffff);

    this.graphics = this.add.graphics();
    this.graphics.fillStyle(0x000000);
    let textures = ["bar", "block1", "block2", "block3", "rect"]

    let rand = ["bar", "block1", "block2", "block3", "rect"]

    this.obj = this.CreateVerts(Phaser.Math.Between(0, this.sys.canvas.width), Phaser.Math.Between(0, this.sys.canvas.height / 2), rand[Phaser.Math.FloorTo(Phaser.Math.Between(0, rand.length - 1))])
    this.obj.setVelocity(6, 3);
    this.obj.setAngularVelocity(0.01);
    this.obj.setBounce(1);
    this.obj.setFriction(0, 0, 0);
}
        
update() {
    let rand = ["bar", "block1", "block2", "block3", "rect"]

    if (this.input.activePointer.isDown) {
        this.GetPixel(this.obj.x, this.obj.y, this.obj.rotation, this.obj.texture.key)
        this.obj.destroy();
        this.obj = this.CreateVerts(Phaser.Math.Between(0, this.sys.canvas.width), Phaser.Math.Between(0, this.sys.canvas.height / 2), rand[Phaser.Math.FloorTo(Phaser.Math.Between(0, rand.length - 1))])
        this.obj.setAngularVelocity(1);

    }

    this.graphicsSub.clear();

    for (let p of this.geomPoints) {
        this.graphicsSub.fillRect(p.x, p.y , p.z,p.z)
    }

}

public GetPixel(x: number, y: number, rotate:number,key: string) {
    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) {
                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)

            }
        }
    }
}

実行結果がこちらです。 f:id:Phaser_3:20190125144841g:plain 粉砕エフェクトができていると思います。
今回のソースはこちらです。

/// <reference path="../app.ts" />

namespace MyGame {

    interface XY {
        x: number;
        y: number;
    }

    export class Vert {
        public point: Phaser.Math.Vector2;
        public next1: Phaser.Math.Vector2;
        public next2: Phaser.Math.Vector2;
        constructor(p: Phaser.Math.Vector2, n1: Phaser.Math.Vector2, n2: Phaser.Math.Vector2, ) {
            this.point = p;
            this.next1 = n1;
            this.next2 = n2;
        }
    }


    export class MyScene1 extends Phaser.Scene {

        //グラフィックオブジェクトを用意
        public player: Phaser.GameObjects.Image;
        public beamGroup: Phaser.GameObjects.Group;

        public graphics: Phaser.GameObjects.Graphics;
        public graphicsSub: Phaser.GameObjects.Graphics;
        public points: Phaser.Math.Vector2[] = [];
        public closepath: Phaser.Math.Vector2[] = [];
        public pixels: number[][];
        public imageData: ImageData;
        public pixelsCopy: number[][];

        public border: Phaser.Math.Vector2[] = [];
        public verts: { [key: string]: Phaser.Math.Vector2[] } = {};
        public canvas: Phaser.Textures.CanvasTexture;
        public obj: Phaser.Physics.Matter.Sprite;
        public point: Phaser.Math.Vector3;
        public geomPoints:Phaser.Math.Vector3[]=[]


        constructor() {
            super({ key: 'MyScene1', active: false });
        }

        preload() {
            this.load.image("bar", "assets/images/bar.png");
            this.load.image("block1", "assets/images/block1.png");
            this.load.image("block2", "assets/images/block2.png");
            this.load.image("block3", "assets/images/block3.png");
            this.load.image("rect", "assets/images/rect32.png");
            this.load.image("pixel", "assets/images/2x2.png");
        }

        public CreateVerts(x: number, y: number, texture: string) {
            this.points = [];
            this.closepath = [];
            this.border = [];

            //phaserのテクスチャマネージャからsourceimageを取得する
            let source = this.textures.get(texture).getSourceImage();;

            if (this.verts[texture] === undefined) {

                //canvasを作成しテクスチャを描画
                this.canvas = this.textures.createCanvas(texture + "_canvas", source.width, source.height);
                this.canvas.clear()
                this.canvas.draw(0, 0, source as HTMLImageElement);

                //imagedataを取得
                this.imageData = this.canvas.imageData;
                this.pixels = new Array();
                this.pixelsCopy = new Array();
                //ピクセルを配列に入れる
                for (let i = 0; i < this.canvas.imageData.data.length; i += 4) {
                    let p = [this.canvas.imageData.data[i], this.canvas.imageData.data[i + 1], this.canvas.imageData.data[i + 2], this.canvas.imageData.data[i + 3]]
                    this.pixels.push(p);
                }

                //ピクセルを配列にいれなおす
                for (let i = 0; i < this.imageData.height; i++) {
                    this.pixelsCopy[i] = new Array();
                    for (let j = 0; j < this.imageData.width; j++) {
                        this.pixelsCopy[i].push(0)
                    }
                }

                let xx = 0;
                let yy = 0;

                //アルファ値の取得
                for (let i = 0; i < this.pixels.length; i++) {

                    this.pixelsCopy[yy][xx] = this.pixels[i][3]
                    xx++;

                    if (xx === source.width) {
                        xx = 0;
                        yy++;
                    }
                }

                let origin = 0;
                let tmp = new Phaser.Math.Vector2(0);

                while (this.pixels[origin][3] === 0) {
                    origin++;
                }

                let mov = new Phaser.Math.Vector2(0, 0);
                tmp = this.GetBoarder(new Phaser.Math.Vector2(origin, 0), mov);

                this.border.push(new Phaser.Math.Vector2(origin, 0))

                let prevmov = new Phaser.Math.Vector2(mov.x, mov.y);

                while (!(tmp.x === origin && tmp.y === 0)) {
                    tmp = this.GetBoarder(tmp, mov);
                    if (!(prevmov.x === mov.x && prevmov.y === mov.y)) {
                        this.border.push(new Phaser.Math.Vector2(tmp.x, tmp.y));
                    }
                    prevmov.set(mov.x, mov.y);
                }

                //取得した輪郭からverticesを作る
                let verts = ""
                for (let p of this.border) {
                    verts += (p.x + x) + " " + (p.y + y) + " "
                }


                var poly = this.add.polygon(x, y, verts, 0x0000ff, 0.2);
                this.verts[texture] = this.border;

                return this.matter.add.sprite(x, y, texture, 0, { shape: { type: 'fromVerts', verts: verts, flagInternal: false }, label: texture }).setTint(0x05FBFF, 0x1E00FF0);

            } else {
                let verts = ""

                for (let p of this.verts[texture]) {
                    verts += (p.x + x) + " " + (p.y + y) + " "
                }

                return this.matter.add.sprite(x, y, texture, 0, { shape: { type: 'fromVerts', verts: verts, flagInternal: false }, label: texture}).setTint(0x05FBFF, 0x1E00FF0);
                
            }

        }

        create() {
            this.graphicsSub = this.add.graphics();
            this.point = new Phaser.Math.Vector3(0, 0,0);
            this.matter.world.setBounds();

            this.cameras.main.setBackgroundColor(0xffffff);

            this.graphics = this.add.graphics();
            this.graphics.fillStyle(0x000000);
            let textures = ["bar", "block1", "block2", "block3", "rect"]

            let rand = ["bar", "block1", "block2", "block3", "rect"]

            this.obj = this.CreateVerts(Phaser.Math.Between(0, this.sys.canvas.width), Phaser.Math.Between(0, this.sys.canvas.height / 2), rand[Phaser.Math.FloorTo(Phaser.Math.Between(0, rand.length - 1))])
            this.obj.setVelocity(6, 3);
            this.obj.setAngularVelocity(0.01);
            this.obj.setBounce(1);
            this.obj.setFriction(0, 0, 0);
        }
        
        update() {
            let rand = ["bar", "block1", "block2", "block3", "rect"]

            if (this.input.activePointer.isDown) {
                this.GetPixel(this.obj.x, this.obj.y, this.obj.rotation, this.obj.texture.key)
                this.obj.destroy();
                this.obj = this.CreateVerts(Phaser.Math.Between(0, this.sys.canvas.width), Phaser.Math.Between(0, this.sys.canvas.height / 2), rand[Phaser.Math.FloorTo(Phaser.Math.Between(0, rand.length - 1))])
                this.obj.setAngularVelocity(1);

            }

            this.graphicsSub.clear();

            for (let p of this.geomPoints) {
                this.graphicsSub.fillRect(p.x, p.y , p.z,p.z)
            }

        }

        public GetPixel(x: number, y: number, rotate:number,key: string) {
            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) {
                        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)

                    }
                }
            }

        }


        //衝突を処理するための関数
        public GetCollide(body): Phaser.Physics.Arcade.Body {
            if (body.parent === body) {
                return body;
            }
            while (body.parent !== body) {
                body = body.parent;
            }
            return body;

        }

        public GetBoarder(v: Phaser.Math.Vector2, m: Phaser.Math.Vector2): Phaser.Math.Vector2 {
            let r: Phaser.Math.Vector2 = null;

            //左下のピクセルから調べていく
            let dir1 = () => {
                if (v.x > 0 && v.y < this.imageData.height - 1) {
                    if (this.pixelsCopy[v.y + 1][v.x - 1] !== 0) {
                        m.set(-1, 1);
                        return new Phaser.Math.Vector2(v.x - 1, v.y + 1);
                    }
                }
                return null;
            }

            //下
            let dir2 = () => {
                if (v.y < this.imageData.height - 1 && !(m.x == 0 && m.y == -1)) {
                    if (this.pixelsCopy[v.y + 1][v.x] !== 0) {
                        m.set(0, 1);
                        return new Phaser.Math.Vector2(v.x, v.y + 1);
                    }
                }
                return null;
            }

            //右下
            let dir3 = () => {
                if (v.x < this.imageData.width - 1 && v.y < this.imageData.height - 1) {
                    if (this.pixelsCopy[v.y + 1][v.x + 1] !== 0) {
                        m.set(1, 1);
                        return new Phaser.Math.Vector2(v.x + 1, v.y + 1);
                    }
                }
                return null;

            }

            //右
            let dir4 = () => {
                if (v.x < this.imageData.width - 1) {
                    if (this.pixelsCopy[v.y][v.x + 1] !== 0) {
                        m.set(1, 0);
                        return new Phaser.Math.Vector2(v.x + 1, v.y);
                    }
                }
                return null;
            }

            //右上
            let dir5 = () => {
                if (v.x < this.imageData.width - 1 && v.y > 0) {
                    if (this.pixelsCopy[v.y - 1][v.x + 1] !== 0) {
                        m.set(1, -1);
                        return new Phaser.Math.Vector2(v.x + 1, v.y - 1);
                    }
                }
                return null;
            }

            //上
            let dir6 = () => {
                if (v.y > 0) {
                    if (this.pixelsCopy[v.y - 1][v.x] !== 0) {
                        m.set(0, -1);
                        return new Phaser.Math.Vector2(v.x, v.y - 1);
                    }
                }
                return null;
            }


            //左上
            let dir7 = () => {
                if (v.x > 0 && v.y > 0) {
                    if (this.pixelsCopy[v.y - 1][v.x - 1] !== 0) {
                        m.set(-1, -1);
                        return new Phaser.Math.Vector2(v.x - 1, v.y - 1);
                    }
                }
                return null;
            }

            //左
            let dir8 = () => {
                if (v.x > 0) {
                    if (this.pixelsCopy[v.y][v.x - 1] !== 0) {
                        m.set(-1, 0);
                        return new Phaser.Math.Vector2(v.x - 1, v.y);
                    }
                }
                return null;
            }

            if (m.x === -1 && m.y === 1) {
                r = dir7();
                if (r !== null) {
                    return r;
                }
                r = dir8();
                if (r !== null) {
                    return r;
                }
                r = dir1();
                if (r !== null) {
                    return r;
                }
                r = dir2();
                if (r !== null) {
                    return r;
                }
                r = dir3();
                if (r !== null) {
                    return r;
                }
                r = dir4();
                if (r !== null) {
                    return r;
                }
                r = dir5();
                if (r !== null) {
                    return r;
                }
                r = dir6();
            }

            if (m.x === 0 && m.y === 1) {
                r = dir1();
                if (r !== null) {
                    return r;
                }
                r = dir2();
                if (r !== null) {
                    return r;
                }
                r = dir3();
                if (r !== null) {
                    return r;
                }
                r = dir4();
                if (r !== null) {
                    return r;
                }
                r = dir5();
                if (r !== null) {
                    return r;
                }
                r = dir6();
                if (r !== null) {
                    return r;
                }
                r = dir7();
                if (r !== null) {
                    return r;
                }
                r = dir8();
                if (r !== null) {
                    return r;
                }
            }

            if (m.x === 1 && m.y === 1) {
                r = dir1();
                if (r !== null) {
                    return r;
                }
                r = dir2();
                if (r !== null) {
                    return r;
                }
                r = dir3();
                if (r !== null) {
                    return r;
                }
                r = dir4();
                if (r !== null) {
                    return r;
                }
                r = dir5();
                if (r !== null) {
                    return r;
                }
                r = dir6();
                if (r !== null) {
                    return r;
                }
                r = dir7();
                if (r !== null) {
                    return r;
                }
                r = dir8();
                if (r !== null) {
                    return r;
                }
            }

            if (m.x === 1 && m.y === 0) {
                r = dir3();
                if (r !== null) {
                    return r;
                }
                r = dir4();
                if (r !== null) {
                    return r;
                }
                r = dir5();
                if (r !== null) {
                    return r;
                }
                r = dir6();
                if (r !== null) {
                    return r;
                }
                r = dir7();
                if (r !== null) {
                    return r;
                }
                r = dir8();
                if (r !== null) {
                    return r;
                }
                r = dir1();
                if (r !== null) {
                    return r;
                }
                r = dir2();
                if (r !== null) {
                    return r;
                }
            }

            if (m.x === 1 && m.y === -1) {
                r = dir3();
                if (r !== null) {
                    return r;
                }
                r = dir4();
                if (r !== null) {
                    return r;
                }
                r = dir5();
                if (r !== null) {
                    return r;
                }
                r = dir6();
                if (r !== null) {
                    return r;
                }
                r = dir7();
                if (r !== null) {
                    return r;
                }
                r = dir8();
                if (r !== null) {
                    return r;
                }
                r = dir1();
                if (r !== null) {
                    return r;
                }
                r = dir2();
                if (r !== null) {
                    return r;
                }
                if (r !== null) {
                    return r;
                }
            }

            if (m.x === 0 && m.y === -1) {
                r = dir5();
                if (r !== null) {
                    return r;
                }
                r = dir6();
                if (r !== null) {
                    return r;
                }
                r = dir7();
                if (r !== null) {
                    return r;
                }
                r = dir8();
                if (r !== null) {
                    return r;
                }
                r = dir1();
                if (r !== null) {
                    return r;
                }
                r = dir2();
                if (r !== null) {
                    return r;
                }
                r = dir3();
                if (r !== null) {
                    return r;
                }
                r = dir4();
                if (r !== null) {
                    return r;
                }
            }

            if (m.x === -1 && m.y === -1) {
                r = dir5();
                if (r !== null) {
                    return r;
                }
                r = dir6();
                if (r !== null) {
                    return r;
                }
                r = dir7();
                if (r !== null) {
                    return r;
                }
                r = dir8();
                if (r !== null) {
                    return r;
                }
                r = dir1();
                if (r !== null) {
                    return r;
                }
                r = dir2();
                if (r !== null) {
                    return r;
                }
                r = dir3();
                if (r !== null) {
                    return r;
                }
                r = dir4();
                if (r !== null) {
                    return r;
                }
            }

            if (m.x === -1 && m.y === 0) {
                r = dir7();
                if (r !== null) {
                    return r;
                }
                r = dir8();
                if (r !== null) {
                    return r;
                }
                r = dir1();
                if (r !== null) {
                    return r;
                }
                r = dir2();
                if (r !== null) {
                    return r;
                }
                r = dir3();
                if (r !== null) {
                    return r;
                }
                r = dir4();
                if (r !== null) {
                    return r;
                }
                r = dir5();
                if (r !== null) {
                    return r;
                }
                r = dir6();
                if (r !== null) {
                    return r;
                }
            }

            if (m.x === 0 && m.y === 0) {
                r = dir1();
                if (r !== null) {
                    return r;
                }
                r = dir2();
                if (r !== null) {
                    return r;
                }
                r = dir3();
                if (r !== null) {
                    return r;
                }
                r = dir4();
                if (r !== null) {
                    return r;
                }
                r = dir5();
                if (r !== null) {
                    return r;
                }
                r = dir6();
                if (r !== null) {
                    return r;
                }
                r = dir7();
                if (r !== null) {
                    return r;
                }
                r = dir8();
                if (r !== null) {
                    return r;
                }
            }
            return null;
        }
    }
}