「The Nature of Code」から様々な境界について取り上げます。境界といっても直線ばかりではありません。ここでは、パーリンノイズと正弦波で境界を作ります。Processingでプログラムを書いて、動作を確認します。動作を確認できるところがProcessingの楽しいところです。
パーリンノイズで境界を描く
以下は、パーリンノイズで境界を描く参考例です。
//NoiseChain import shiffman.box2d.*; import org.jbox2d.collision.shapes.*; import org.jbox2d.common.*; import org.jbox2d.dynamics.*; Box2DProcessing box2d; ArrayList<Particle> particles; Surface surface; void setup(){ size(200, 200); box2d = new Box2DProcessing(this); box2d.createWorld(); //重力 box2d.setGravity(0, -10); particles = new ArrayList<Particle>(); surface = new Surface(); } void draw(){ background(255); box2d.step(); //particlesの追加 if(random(1) < 0.2){ float sz = random(4, 8); particles.add(new Particle(width/2, 30, sz)); } //境界の表示 surface.display(); //particlesの表示 for(Particle p : particles){ p.display(); } //ウィンドウから外れたparticlesをbox2dとリストから削除 for(int i = particles.size()-1; i >=0; i--){ Particle p = particles.get(i); if(p.done()){ particles.remove(i); //println("delete"); } } }
class Particle{ Body body; float r; //コンストラクタ Particle(float x, float y, float r_){ r = r_; //box2dにパーティクルを設定する makeBody(x, y, r); } //box2dからパーティクルを削除 void killBody(){ box2d.destroyBody(body); } //パーティクルの生存判定 boolean done(){ //パーティクルの位置 Vec2 pos = box2d.getBodyPixelCoord(body); //ウィンドウから外れているときの処理 if(pos.y > height+r*2){ killBody(); return true; } return false; } //図形の描画 void display(){ Vec2 pos = box2d.getBodyPixelCoord(body); float a = body.getAngle(); pushMatrix(); translate(pos.x, pos.y); rotate(-a); fill(175); stroke(0); strokeWeight(2); ellipse(0, 0, r*2, r*2); line(0, 0, r, 0); popMatrix(); } //box2dにパーティクルを設定する void makeBody(float x, float y, float r){ //ボディの定義 BodyDef bd = new BodyDef(); bd.type = BodyType.DYNAMIC; bd.position.set(box2d.coordPixelsToWorld(x, y)); body = box2d.createBody(bd); //形状の定義 CircleShape cs = new CircleShape(); cs.m_radius = box2d.scalarPixelsToWorld(r); FixtureDef fd = new FixtureDef(); fd.shape = cs; fd.density = 1; fd.friction = 0.01; fd.restitution = 0.3; body.createFixture(fd); //速度と角速度の初期値をランダムとする body.setLinearVelocity(new Vec2(random(-10f, 10f), random(5f, 10f))); body.setAngularVelocity(random(-10, 10)); } }
//パーリンノイズの境界 class Surface{ ArrayList<Vec2> surface; //コンストラクタ Surface(){ surface = new ArrayList<Vec2>(); ChainShape chain = new ChainShape(); float xoff = 0.0; //頂点のデータを作成 for(float x = width+10; x > -10; x -= 5){ float y; if(x > width/2){ y = 50 + (width-x) * 1.1 + map(noise(xoff), 0, 1, -80, 80); }else{ y = 50 + x * 1.1 + map(noise(xoff), 0, 1, -40, 40); } surface.add(new Vec2(x, y)); xoff += 0.1; } //頂点用の配列 Vec2[] vertices = new Vec2[surface.size()]; for(int i = 0; i < vertices.length; i++){ vertices[i] = box2d.coordPixelsToWorld(surface.get(i)); } chain.createChain(vertices, vertices.length); //ボディの定義 BodyDef bd = new BodyDef(); Body body = box2d.world.createBody(bd); body.createFixture(chain, 1); } //図形の描画 void display(){ strokeWeight(2); stroke(0); noFill(); beginShape(); for(Vec2 v: surface){ vertex(v.x, v.y); } endShape(); } }
正弦波の境界を描く
以下は、正弦波で境界を描く参考例です。
//SineChain import shiffman.box2d.*; import org.jbox2d.collision.shapes.*; import org.jbox2d.common.*; import org.jbox2d.dynamics.*; Box2DProcessing box2d; ArrayList<Particle> particles; Surface surface; void setup(){ size(200, 200); box2d = new Box2DProcessing(this); box2d.createWorld(); //重力 box2d.setGravity(0, -10); particles = new ArrayList<Particle>(); surface = new Surface(); } void draw(){ background(255); box2d.step(); //particlesの追加 if(random(1) < 0.2){ float sz = random(4, 8); particles.add(new Particle(width/2, 30, sz)); } //境界の表示 surface.display(); //particlesの表示 for(Particle p : particles){ p.display(); } //ウィンドウから外れたparticlesをbox2dとリストから削除 for(int i = particles.size()-1; i >=0; i--){ Particle p = particles.get(i); if(p.done()){ particles.remove(i); //println("delete"); } } }
class Particle{ Body body; float r; //コンストラクタ Particle(float x, float y, float r_){ r = r_; //box2dにパーティクルを設定する makeBody(x, y, r); } //box2dからパーティクルを削除 void killBody(){ box2d.destroyBody(body); } //パーティクルの生存判定 boolean done(){ //パーティクルの位置 Vec2 pos = box2d.getBodyPixelCoord(body); //ウィンドウから外れているときの処理 if(pos.y > height+r*2){ killBody(); return true; } return false; } //図形の描画 void display(){ Vec2 pos = box2d.getBodyPixelCoord(body); float a = body.getAngle(); pushMatrix(); translate(pos.x, pos.y); rotate(-a); fill(175); stroke(0); strokeWeight(2); ellipse(0, 0, r*2, r*2); line(0, 0, r, 0); popMatrix(); } //box2dにパーティクルを設定する void makeBody(float x, float y, float r){ //ボディの定義 BodyDef bd = new BodyDef(); bd.type = BodyType.DYNAMIC; bd.position.set(box2d.coordPixelsToWorld(x, y)); body = box2d.createBody(bd); //形状の定義 CircleShape cs = new CircleShape(); cs.m_radius = box2d.scalarPixelsToWorld(r); FixtureDef fd = new FixtureDef(); fd.shape = cs; fd.density = 1; fd.friction = 0.01; fd.restitution = 0.3; body.createFixture(fd); //速度の初期値をランダムとする body.setLinearVelocity(new Vec2(random(-10f, 10f), random(5f, 10f))); body.setAngularVelocity(random(-10, 10)); } }
//正弦波の境界 class Surface{ ArrayList<Vec2> surface; //コンストラクタ Surface(){ surface = new ArrayList<Vec2>(); ChainShape chain = new ChainShape(); float theta = 0; //頂点のデータを作成 for(float x = width+10; x > -10; x -= 5){ float y = map(sin(theta), -1, 1, 75, height-10); theta += 0.15; surface.add(new Vec2(x, y)); } //頂点用の配列 Vec2[] vertices = new Vec2[surface.size()]; for(int i = 0; i < vertices.length; i++){ vertices[i] = box2d.coordPixelsToWorld(surface.get(i)); } chain.createChain(vertices, vertices.length); //ボディの定義 BodyDef bd = new BodyDef(); bd.position.set(0.0f, 0.0f); Body body = box2d.world.createBody(bd); body.createFixture(chain, 1); } //図形の描画 void display(){ strokeWeight(2); stroke(0); noFill(); beginShape(); for(Vec2 v: surface){ vertex(v.x, v.y); } endShape(); } }
まとめ
「The Nature of Code」から様々な境界について取り上げました。パーリンノイズと正弦波で境界を作りました。引き続き、「The Nature of Code」の内容を勉強します。
参考書籍
※Javaの勉強にもなるので一石二鳥です。