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; } }
実行結果がこちらです。
輪郭が左側に向かうところで左下に下がっていってしまいます。
ループの構造が適当だったので当たり前の結果です。
力技で解決する
うまい方法が思い浮かばず、各方向への探索関数を作って前回探索時のベクトルで場合分けする方法をためしてみました。
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; } }
実行結果がこちらです。
なにはともあれ一応輪郭の取得はできているように思います。
別スプライトで実行した様子です。
次回以降はソースを整理して輪郭追跡を実用にうつしてみたいと思います。