「The Nature of Code」からポリゴンについて取り上げます。複雑な形状の面を頂点座標を用いて作ります。Processingでプログラムを書いて、動作を確認します。動作を確認できるところがProcessingの楽しいところです。
ポリゴン
ポリゴンとは多角形のことです。頂点座標を用意して、ポリゴンを作ります。頂点座標を任意の値に変更して、形状をカスタマイズできます。
以下は、ポリゴンの参考例です。
//Polygon shapes import shiffman.box2d.*; import org.jbox2d.collision.shapes.*; import org.jbox2d.common.*; import org.jbox2d.dynamics.*; Box2DProcessing box2d; ArrayList<Boundary> boundaries; ArrayList<CustomShape> polygons; void setup(){ size(200, 200); box2d = new Box2DProcessing(this); box2d.createWorld(); //重力 box2d.setGravity(0, -10); //空のArrayListの生成 boundaries = new ArrayList<Boundary>(); polygons = new ArrayList<CustomShape>(); //境界の追加 boundaries.add(new Boundary(width/4, height-5, width/2-50, 10, 0)); boundaries.add(new Boundary(3*width/4, height-5, width/2-50, 10, 0)); boundaries.add(new Boundary(width-5, height/2, 10, height, 0)); boundaries.add(new Boundary(5, height/2, 10, height, 0)); } void draw(){ background(255); box2d.step(); //境界の描画 for(Boundary wall: boundaries){ wall.display(); } //カスタムシェイプの生成・追加 if(random(1) < 0.2){ CustomShape cs = new CustomShape(width/2, 30); polygons.add(cs); } //カスタムシェイプの描画 for(CustomShape cs: polygons){ cs.display(); } //ウィンドウから外れたら削除する for(int i = polygons.size()-1; i >=0; i--){ CustomShape cs = polygons.get(i); if(cs.done()){ polygons.remove(i); } } }
class Boundary{ float x; float y; float w; float h; Body b; //コンストラクタ Boundary(float x_, float y_, float w_, float h_, float a){ x = x_; y = y_; w = w_; h = h_; //ポリゴンの定義 PolygonShape sd = new PolygonShape(); float box2dW = box2d.scalarPixelsToWorld(w/2); float box2dH = box2d.scalarPixelsToWorld(h/2); sd.setAsBox(box2dW, box2dH); //ボディの定義 BodyDef bd = new BodyDef(); bd.type = BodyType.STATIC; bd.angle = a; bd.position.set(box2d.coordPixelsToWorld(x, y)); b = box2d.createBody(bd); b.createFixture(sd, 1); } //図形の描画 void display(){ fill(0); stroke(0); strokeWeight(1); rectMode(CENTER); float a = b.getAngle(); pushMatrix(); translate(x, y); rotate(-a); rect(0, 0, w, h); popMatrix(); } }
class CustomShape{ Body body; //コンストラクタ CustomShape(float x, float y){ //box2dにカスタムシェイプを設定する makeBody(new Vec2(x, y)); } //パーティクルの削除 void killBody(){ box2d.destroyBody(body); } //パーティクルの削除判定 boolean done(){ Vec2 pos = box2d.getBodyPixelCoord(body); if(pos.y > height){ killBody(); return true; } return false; } //図形の描画 void display(){ Vec2 pos = box2d.getBodyPixelCoord(body); float a = body.getAngle(); //フィクスチャリストの取得 Fixture f = body.getFixtureList(); //シェイプを取得 PolygonShape ps = (PolygonShape)f.getShape(); rectMode(CENTER); pushMatrix(); translate(pos.x, pos.y); rotate(-a); fill(127); stroke(0); strokeWeight(2); beginShape(); for(int i = 0; i < ps.getVertexCount(); i++){ //カスタムシェイプの頂点の取得 Vec2 v = box2d.vectorWorldToPixels(ps.getVertex(i)); vertex(v.x, v.y); } endShape(CLOSE); popMatrix(); } //box2dにカスタムシェイプを設定する void makeBody(Vec2 center){ //カスタムシェイプの頂点の配列 Vec2[] vertices = new Vec2[4]; vertices[0] = box2d.vectorPixelsToWorld(new Vec2(-5, 5)); vertices[1] = box2d.vectorPixelsToWorld(new Vec2(5, 4)); vertices[2] = box2d.vectorPixelsToWorld(new Vec2(2, -5)); vertices[3] = box2d.vectorPixelsToWorld(new Vec2(-2, -10)); //ポリゴンの定義 PolygonShape ps = new PolygonShape(); ps.set(vertices, vertices.length); //ボディの定義 BodyDef bd = new BodyDef(); bd.type = BodyType.DYNAMIC; bd.position.set(box2d.coordPixelsToWorld(center)); body = box2d.createBody(bd); body.createFixture(ps, 1.0); //初速度はランダム body.setLinearVelocity(new Vec2(random(-5, 5), random(2, 5))); body.setAngularVelocity(random(-5, 5)); } }
注意点
- 頂点の順序
- ピクセルで考える場合、頂点を反時計回りの順序で定義する
- Box2Dに座標を変換すると垂直軸が反転するため
- 形は凸型のみ
- Box2Dでは凹型シェイプの衝突を処理できないため
- 凹型を作る場合は、複数の凸型から作る
まとめ
「The Nature of Code」からポリゴンについて取り上げました。複雑な形状の面を頂点座標を用いて作りました。引き続き、「The Nature of Code」の内容を勉強します。
参考書籍
※Javaの勉強にもなるので一石二鳥です。