3.1 運動1

この節では、オブジェクトを動かしてみます。
ここで必ず使う機能はsetup()draw()です。このモードはProcessingプログラミングの中で一番よく使われるものです。
setup()で初期化し、draw()を繰り返し実行することでアニメーションやインタラクションを実現します。次の点を理解しておきましょう。

・setup()は一度だけ実行される
・draw()はプログラムが動いている間は常に繰り返される

3.1.1 簡単な運動

まずは、ともかく動くものを作ってみましょう。第一歩は、左から右に円が移動するだけの簡単な動きです。

2016_06_16_0_38
図3.1-a
リスト3.1-a
int eSize = 20;  //オブジェクトのサイズ
int velocity = 5;  //オブジェクトのスピード
int x = 0;  //オブジェクトのx座標

//初期化
void setup() {
  size(400, 400);
  background(255);      //背景色
  noStroke();      //輪郭を描かない
  fill(0);      //オブジェクトを黒で塗りつぶす
}

//ひたすら{ }で囲まれた中を繰り返す
void draw() {
  background(255);  //画面の色を更新

  //軌跡を残す場合は、下の3行をON、backgoundをOFFにする
  /*
  fill(255, 50);  //透明度のあるrectを描画
  rect(0, 0, width, height);
  fill(0);      //オブジェクトは黒
  */

  ellipse(x, height/2, eSize, eSize);    //円を描く
  x += velocity;    //x座標にvelocityの値を足す
}

draw()の { } で囲まれた部分がひたすら繰り返されるので、x座標の値が加算されることによって、円が動いているように見えるのです。
プログラミングにおける運動の記述は、全てこの原理に基づいています。

3.1.2 運動の繰り返し

前述のサンプルのように、x座標がひたすら増えていった場合、オブジェクトが画面の外に出てしまったらその先がどうなったか分かりません。ということで、同じ運動を繰り返すように改変してみましょう。次のサンプルでは、円が画面の右端まで行くと左端に戻ってまた同じ動きが再現されます【リスト3.1-b】。

2016_06_16_0_44
図3.1-b
リスト3.1-b
int eSize = 20;  //オブジェクトのサイズ
int velocity = 5;  //オブジェクトのスピード
int x = 0;  //オブジェクトのx座標

//初期化
void setup() {
  size(400, 400);
  background(255);  //背景は白
  noStroke();      //輪郭を描かない
  fill(0);      //オブジェクトを黒で塗りつぶす
}

//プログラムが終了するまで、draw()の中は繰り返される
void draw() {
  background(255);  //画面の色を更新

  ellipse(x, height/2, eSize, eSize);    //円を描く
  x += velocity;    //x座標にvelocityの値を足す

  //もし、xの値が画面の幅以上になったら、xを0に戻す
  if (x >= width) {    
    x = 0;
  }
}

3.1.3 加減速

velocityの値が段階的に増減すると、加速と減速が可能になります。次のサンプルでは、vControlという変数の値を増減しています【リスト3.1-c】。

2016_06_16_0_55
図3.1-c
リスト3.1-c
int eSize = 20;  //オブジェクトのサイズ
float velocity = 0.0;  //オブジェクトのスピード
float vControl = 0.2;  //スピードのコントロール
float maxVel = 10.0;  //スピードの最大値
float x = 0.0;  //オブジェクトのx座標

//初期化
void setup() {
  size(400, 400);
  background(255);  //背景は白
  noStroke();      //輪郭を描かない
  fill(0);      //オブジェクトを黒で塗りつぶす
}

//プログラムが終了するまで、draw()の中は繰り返される
void draw() {
  background(255);  //画面の色を更新

  ellipse(x, height/2, eSize, eSize);    //円を描く

  //スピードが最大か0になったらvControlを反転
  if (velocity > maxVel || velocity < 0.0) {
    vControl = -vControl;
  }
  x += velocity;    //x座標にvelocityの値を足す
  velocity += vControl;

  //もし、xの値が画面の幅以上になったら、xを0に戻す
  if (x >= width) {
    x = 0;
  }
}

3.1.4 バウンド

次は、円が画面の端まで行ったらバウンドするサンプルです。

2016_06_16_0_48
図3.1-d
リスト3.1-d
int eSize = 20;  //オブジェクトのサイズ
int velocity = 5;  //オブジェクトのスピード
int x = 0;  //オブジェクトのx座標

//初期化
void setup() {
  size(400, 400);
  background(255);  //背景は白
  noStroke();      //輪郭を描かない
  fill(0);  //黒で描く
}

//プログラムが終了するまで、draw()の中は繰り返される
void draw() {
  background(255);  //画面の色を更新

  x += velocity;    //xの値にvelocityを足す

  ellipse(x, height/2, eSize, eSize);    //円を描く

  //もし、xの値が画面の右端より大きくなるか、左端より小さくなった場合、
  if (x > width || x < 0) {
    velocity = -velocity;    //velocityの正負を入れ替える
  }
}

また、上下左右の動きもバウンドさせることができます。

2016_06_16_1_00
図3.1-e
リスト3.1-e
int eSize = 20;  //オブジェクトのサイズ
int velX = 5;  //x方向のスピード
int velY = 2;  //y方向のスピード
int x = 0;  //x座標
int y = 0;  //y座標

//初期化
void setup() {
  size(400, 400);
  background(255);  //背景は白
  noStroke();      //輪郭を描かない
  fill(0);  //黒で描く
}

//プログラムが終了するまで、draw()の中は繰り返される
void draw() {
  background(255);  //画面の色を更新

  x += velX;    //xの値にvelXを足す
  y += velY;    //yの値にvelYを足す

  ellipse(x, y, eSize, eSize);    //円を描く

  //もし、xの値が画面の右端より大きくなるか、左端より小さくなった場合、
  if (x > width || x < 0) {
    velX = -velX;    //speedの正負を入れ替える
  }

  //もし、yの値が画面の高さより大きくなるか、上端より小さくなった場合、
  if (y > height || y < 0) {
    velY = -velY;    //speedの正負を入れ替える
  }
}

3.1.5 2次関数

さすがに直線運動だけだとバリエーションが広がらないので、曲線運動を記述してみましょう。2次関数は次の式で表すことができます。

y=ax2

これを、コードにすると次のような形になります【リスト3.1-f】。

2016_06_11_15_36
図3.1-f
リスト3.1-f
float x = 0.0;  //円のx座標は0から始める
float y;  //円のy座標
float velocity = 0.02;  //円のスピード
float resize = 200.0;  //ピクセルの拡大率

//初期化
void setup() {
  size(400, 400);
  background(255);
}

//プログラムが終了するまで、draw()の中は繰り返される
void draw() {
  background(255);

  stroke(200);
  line(0, height/2, width, height/2);  //基準線
  line(width/2, 0, width/2, height);

  x += velocity;  //xにスピードを加算

  //y座標はxの2乗
  //xが-1.0~1.0なので、yは0~1.0になる
  y = x*x;

  //参考: 3次関数
  //y = x * x * x;  

  //xは-1.0~1.0の間を往復する
  if (x > 1.0 || x < -1.0) {
    velocity = -velocity;
  }

  noStroke();

  //x座標のみの変化
  fill(0);
  ellipse(x*resize + width/2, height/2, 20, 20);

  //y座標のみの変化
  fill(0, 0, 255);
  ellipse(width/2, height/2 - y*resize, 20, 20);

  //2次曲線
  fill(255, 0, 0);
  ellipse(x*resize + width/2, height/2 - y*resize, 20, 20);
}

3.1.6 色彩の変化

当然、x, y軸を変えるだけではなく、色彩も変化させることが出来ます。次のサンプルを実行してみましょう【リスト3.1-g】。

2016_06_11_14_26
図3.1-g
リスト3.1-g
int gray;  //grayの値
int speed;  //色の変化のスピード

//初期化
void setup() {
  size(400, 400);
  gray = 0;  //grayの初期初期値は0
  speed = 5;    //スピードの初期設定
}

//プログラムが終了するまで、draw()の中は繰り返される
void draw() {

  gray += speed;    //grayの値にspeedを足す

  //もし、grayの値が255より大きくなるか、0より小さくなったら
  if (gray > 255) {

    speed = -speed;  //speedの正負を入れ替える
    gray = 255;  //grayを白にする
    
  } else if (gray < 0) {

    speed = -speed;  //speedの正負を入れ替える
    gray = 0;  //grayを黒にする
  }

  background(gray);  //背景を描く
  //background(gray, 0, 0);  //赤の値だけ変化する
}

例えば、次のサンプルは、赤と緑を変化させていますが、変化のスピードが違うと、予測していなかったような色に変化することもあります。様々な組み合わせを試してみましょう。

2016_06_16_1_05
図3.1-h
リスト3.1-h
float r, g;  //赤、緑のそれぞれの値
float rSpeed, gSpeed;  //赤、緑の変化のスピード
 
//初期化
void setup() {
  size(400, 400);
  r = 0.0;  //赤の初期初期値は0.0
  g = 255.0;//緑の初期初期値は255.0
  rSpeed = 1.0;    //赤の変化するスピード
  gSpeed = 1.2;    //緑の変化するスピード
}
 
//プログラムが終了するまで、draw()の中は繰り返される
void draw() {
 
  r += rSpeed;    //rの値にrSpeedを足す
  g += gSpeed;    //gの値にgSpeedを足す
 
  //もし、r, g, bの値が255(最大値)より大きくなるか、
  //0(最小値)より小さくなった場合、  
  if(r > 255){
    rSpeed = -rSpeed;    //rSpeedの正負を入れ替える
 
    //rの値が255を超えたまま画面表示されるとノイズが入るため
    //255以上にはならないように設定
    r = 255;
  }else if(r < 0) {
    r = 0;
    rSpeed = -rSpeed;    //rSpeedの正負を入れ替える
  }
 
  if(g > 255){
    gSpeed = -gSpeed;    //gSpeedの正負を入れ替える
    g = 255;
  }else if(g < 0) {
    gSpeed = -gSpeed;    //gSpeedの正負を入れ替える
    g = 0;
  }
 
  background(r, g, 0);  //背景を描画
}

3.1.7 タイマー

時間が経ったら次の変化が起こるアニメーションを作りたいとき、タイマーを使うと便利です。
タイマーと言っても今まで学習した変数を使う簡単なもので十分機能します。
次のサンプルを実行してみましょう【リスト3.1-i】。

2016_06_16_1_09
図3.1-i
リスト3.1-i
int timer = 0;  //タイマー
 
//初期化
void setup() {
  size(400, 400);
  noStroke();
  
  //再生速度を1秒30フレームに設定(初期値は1秒60フレーム)
  frameRate(30);
}
 
//プログラムが終了するまで、draw()の中は繰り返される
void draw() {
  background(255);
 
  //時間を計るときには、
  //再生速度が1秒30フレームに設定されているので、秒数に30を掛ける
  if(timer > 3*30 ){    //もし、timerが3秒を超えたら、
    fill(255, 0, 0);     //赤にする
  }else{                 //そうでなかったら
    fill(0, 255, 0);    //緑にする
  }
  ellipse(width/2, height/2, 100, 100); 
 
  if(mousePressed) {    //マウスが押されたら、
    println(timer/30);         //経過時間を出力する(秒)
  }
  timer ++;
}

また、millis()を使うとより正確な時間管理ができます。作品によってふさわしい方法を選びましょう。

リスト3.1-j
//初期化
void setup() {
  size(400, 400);
  noStroke();
}
 
//プログラムが終了するまで、draw()の中は繰り返される
void draw() {
  background(255);
 
  //millis()を宣言すると、
  //プログラムが始まって終了するまで時間をカウントする
  int m = millis();
 
  //1秒=1000msなので、以下のように書くと、
  //mが3秒を超えたら、という意味になる
  if(m > 3*1000 ){    //もし、mが3秒を超えたら
    fill(255, 0, 0);     //赤にする
  }else{                 //それまでは
    fill(0, 255, 0);    //緑にする
  }
  ellipse(width/2, height/2, 100, 100); 
 
  if(mousePressed) {    //マウスが押されたら、
    println(m);         //経過時間を出力する(秒)
  }
}

次のサンプルでは、3秒毎に緑、赤、黄色という色の変化が繰り返されます。繰り返しを実現する為には、%(モジュロ。剰余)を使います。この方法は、アニメーションの繰り返しをおこなう時に非常に便利です。

リスト3.1-k
//初期化
void setup() {
  size(400, 400);
  noStroke();
}

//プログラムが終了するまで、draw()の中は繰り返される
void draw() {
  background(255);

  //mills()を宣言すると、
  //プログラムが始まって終了するまで時間をカウントする
  int m = millis();

  //mは9000で割った余りなので、常に0~8999の間の値を繰り返す
  m = m % (9*1000);

  //もし、mが3秒以下だったら
  if (m <= 3*1000) {

    fill(0, 255, 0);     //緑にする

    //もし、mが3秒超6秒以下だったら
  } else if (m > 3*1000 && m <= 6*1000) {

    fill(255, 0, 0);     //赤にする

    //もし、mが6秒超9秒以下だったら
  } else if (m > 6*1000 && m <= 9*1000) {

    fill(255, 255, 0);     //黄にする
  }

  ellipse(width/2, height/2, 100, 100); 

  if (mousePressed) {    //マウスが押されたら
    println(m);         //経過時間を出力する(秒)
  }
}