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

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

 メニュー

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

Processing:様々な境界

「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の勉強にもなるので一石二鳥です。

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