Phaser3 :凹面の当たり判定を自動で生成してみる⑥ 物理ボディの生成

前回に引き続きメッシュの自動生成を行っていきます。

vertsを設定し物理ボディの作成

前回三角形分割を行いましたが、物理ボディ用の頂点は三角形分割の必要がないらしく、輪郭をそのまま結合して渡すと物理ボディが作成できました。

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

this.matter.world.setBounds();

var poly = this.add.polygon(400, 300, verts, 0x0000ff, 0.2);

this.matter.add.gameObject(poly, { shape: { type: 'fromVerts', verts: verts, flagInternal: false } });

いままでのコードをまとめて物理ボディ作成用のCreateVerts関数を作りました。

        public CreateVerts(x: number, y: number, texture: string) {
            //phaserのテクスチャマネージャからsourceimageを取得する
            let source = this.textures.get(texture).getSourceImage();;

            //canvasを作成しテクスチャを描画
            this.canvas = this.textures.createCanvas(texture+"_canvas", source.width, source.height);
            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)+ " "
            }

            this.matter.world.setBounds();

            var poly = this.add.polygon(400, 300, verts, 0x0000ff, 0.2);

            this.matter.add.gameObject(poly, { shape: { type: 'fromVerts', verts: verts, flagInternal: false } });

        }

実行結果がこちらです。 f:id:Phaser_3:20190115145158g:plain f:id:Phaser_3:20190115145211g:plain f:id:Phaser_3:20190115145621g:plain f:id:Phaser_3:20190115145634g: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 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;

        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");
        }

        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.matter.add.gameObject(poly, { shape: { type: 'fromVerts', verts: verts, flagInternal: false } });
                this.verts[texture] = this.border;

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


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

                this.matter.add.gameObject(poly, { shape: { type: 'fromVerts', verts: verts, flagInternal: false } });

            }

        }

        create() {
            this.matter.world.setBounds();

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

            this.graphics = this.add.graphics();
            this.graphics.fillStyle(0x000000);


        }

        update() {
            let rand = ["bar","block1","block2","block3","rect"]
            if (this.input.activePointer.isDown) {
                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))])

            }
        }
        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;
        }
    }
}