Phaser3: 凹面の当たり判定を自動で生成してみる④ 輪郭追跡の続き

前回に引き続き輪郭追跡の続きを作成します。

前回の位置に基づいて追跡の始点を変える

始点を左下に固定するとある部分でループしてしまうことが判明したので、前回の移動ベクトルに基づいて追跡の始点を変えようと思います。
始点がずれると飛ばした方向の輪郭追跡ができないので、最低でも一周はループさせるようにしてみました。

        public GetBoarder(v: Phaser.Math.Vector2, m: Phaser.Math.Vector2): Phaser.Math.Vector2 {
            let loop = 0;
            let vec = -1;

            if (m.x === -1 && m.y === 1) {
                vec = 0;
            }

            if (m.x === 0 && m.y === 1) {
                vec = 1;
            }

            if (m.x === 1 && m.y === 1) {
                vec = 1;
            }

            if (m.x === 1 && m.y === 0) {
                vec = 2;
            }

            if (m.x === -1 && m.y === -1) {
                vec = 2;
            }

            if (m.x === 0 && m.y === -1) {
                vec = 3;
            }

            if (m.x === -1 && m.y === -1) {
                vec = 3;
            }

            if (m.x === -1 && m.y === 0) {
                vec = 0;
            }

            while (loop === 0) {


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

                //下
                if (vec === 1 || vec === -1) {
                    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);
                            loop = 1;
                            return new Phaser.Math.Vector2(v.x, v.y + 1);
                        }
                    }
                }
                //右下
                if (vec === 1 || vec === -1) {
                    if (v.x < this.imageData.width - 1 && v.y < this.imageData.height - 1 && !(m.x == -1 && m.y == -1)) {
                        if (this.pixelsCopy[v.y + 1][v.x + 1] !== 0) {
                            m.set(1, 1);
                            loop = 1;
                            return new Phaser.Math.Vector2(v.x + 1, v.y + 1);
                        }
                    }
                }
                //右
                if (vec === 2 || vec === -1) {

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

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

                //上
                if (vec === 3 || vec === -1) {

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

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

                    if (v.x > 0 && !(m.x == 1 && m.y == 0)) {
                        if (this.pixelsCopy[v.y][v.x - 1] !== 0) {
                            m.set(-1.0);
                            loop = 1;
                            return new Phaser.Math.Vector2(v.x - 1, v.y);
                        }
                    }
                }

                vec = -1;
            }
            return null;
        }
    }

実行結果がこちらです。 f:id:Phaser_3:20190110192405p:plain 輪郭が左側に向かうところで左下に下がっていってしまいます。
ループの構造が適当だったので当たり前の結果です。

力技で解決する

うまい方法が思い浮かばず、各方向への探索関数を作って前回探索時のベクトルで場合分けする方法をためしてみました。

        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 = () => {
                console.log(v)
                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;
        }
    }

実行結果がこちらです。 f:id:Phaser_3:20190110192708p:plain なにはともあれ一応輪郭の取得はできているように思います。
別スプライトで実行した様子です。 f:id:Phaser_3:20190110192835p:plain

次回以降はソースを整理して輪郭追跡を実用にうつしてみたいと思います。