元Webデザイナー兼コーダーの備忘録

ウェブデザインやプログラミング、ブログのカスタマイズなどについてアウトプットしています。

 メニュー

» HTML入門のまとめはこちらです。

Processing:複雑な形状の面をポリゴンで作る

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

注意点

  1. 頂点の順序
    • ピクセルで考える場合、頂点を反時計回りの順序で定義する
    • Box2Dに座標を変換すると垂直軸が反転するため
  2. 形は凸型のみ
    • Box2Dでは凹型シェイプの衝突を処理できないため
    • 凹型を作る場合は、複数の凸型から作る

まとめ

「The Nature of Code」からポリゴンについて取り上げました。複雑な形状の面を頂点座標を用いて作りました。引き続き、「The Nature of Code」の内容を勉強します。

参考書籍

Javaの勉強にもなるので一石二鳥です。

» HTML入門のまとめはこちらです。