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 } }); }
実行結果がこちらです。
物理ボディを自動生成できているのがわかります。
今回のソースはこちらです。
/// <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; } } }