Processing

11. プログラムを汎用的にする

プログラミングでヴィジュアルを作る面白さの一つは、(最終的なヴァジュアルを作るのではなく)ヴァジュアルの作り方を作る点にあると言えます。

そのための1歩として、簡単なプログラムであっても、なるべく汎用的に作ると良いでしょう。

今までの項目では、例えば線を描く場合であっても、その座標に直接数値を指定していました。変数を利用した方が良い場合は、数値ではなく変数を使い数値を間接的に指定することで、プログラムが汎用的になることがあります。

座標や変更する可能性がある数を変数にしたり、計算で求めたりする 1

例えば「8.繰返し」では、線を21本描くプログラムを以下のように書きました。

size( 500, 500 );
background( 255 );

stroke( #339933 );

for( int i = 0; i < 21; i++ ) {
  line( 50 + i * 20, 50, 50 + i * 20, 450 );
}

このプログラムですが、線の描画位置や本数、長さを検討したり、修正、発展させる可能性があるのであれば、7行目の始点・終点の座標(50とか450とか)や線を描く幅(20)などは変数とした方が良いかもしれません。つまり、以下のように書いた方が望ましい場合があります。

size( 500, 500 );
background( 255 );

int repeatNum = 21;	//繰返しの回数
int linePitch = 20;	//線の間隔

int lineLeftX = 50;	//線を描き始める左端のx座標
int lineTopY = 50;	//線を描き始める上端のy座標

int lineLength = 400;	//線の長さ
int lineBottomY = lineTopY + lineLength;  //線の描き終わりのy座標

stroke( #339933 );

for( int i = 0; i < repeatNum; i++ ) {
  int drawPointX = lineLeftX + i * linePitch;
  line( drawPointX, lineTopY, drawPointX, lineBottomY );
}

line()で使っていた数値を、プログラムの冒頭で定義した変数に置き換えています。

この書き方は、線全体の左上を基準にする書き方になっています。指定したlineLeftX、lineTopYからlinePitch、lineLength、repeatNumの値に応じて(左上を基準に、指定した間隔、長さ、本数に応じて)線が描かれます。

ある程度の本数、長さの場合で、本数や長さを変えても描画範囲の中央に描きたいのであれば、以下のように書いた方が良いでしょう。

size( 500, 500 );
background( 255 );

int repeatNum = 21;	//繰返しの回数
int linePitch = 20;	//線の間隔

int lineLength = 400;	//線の長さ

int linesWidth = linePitch * ( repeatNum - 1 );	//線全体の横幅
int rightLeftX = ( width - linesWidth ) / 2;	//左右の余白
int topBottomY = ( height - lineLength ) / 2;	//上下の余白
int lineBottomY = topBottomY + lineLength;	//線の描き終わりのy座標

stroke( #339933 );

for( int i = 0; i < repeatNum; i++ ) {
  int drawPointX = rightLeftX + i * linePitch;
  line( drawPointX, topBottomY, drawPointX, lineBottomY );
}

9行目、線全体の横幅を線の間隔と繰返しの回数から求めています。

10、11行目、Processingでは、width、heightと書くと、それぞれ画面サイズ(描画範囲)の横幅と高さを得ることができます(ここでいう画面サイズとは、1行目でsize()で指定したサイズのことです)。画面サイズの横幅と高さを利用して、線全体の左右と上下の余白を計算しています。

linePitchやlineLength、repeatNumをある程度の範囲であれば変更しても、線全体が描画範囲の中央に描かれることになります。数値を変えて試してみて下さい。

線全体を中央に1
repeatNum = 30 linePitch = 5 lineLength = 200

線全体を中央に2
repeatNum = 5 linePitch = 50 lineLength = 450

中央に描画するのではなく、上下左右の余白を固定するのであれば、繰返しの回数から線の間隔を計算で求めた方が良いでしょう。

何の値を変数にし、どのような計算で値を求めるかは、どのようなプログラムを書きたいか、どのような変更をする可能性があるかによって異なります。

始めから変数を利用するのが難しければ、このページの冒頭のようにとりあえず数値を使っておき、後からできる部分を変数に置き換えていくなどすると良いでしょう。

ページの先頭へ↑

座標や変更する可能性がある数を変数にしたり、計算で求めたりする 2

同様に「8.繰返し」では、円を縦横に並べるプログラムを以下のように書きました。

size( 500, 500 );
background( 255 );

stroke( #339933 );

for( int i = 0; i < 9; i++ ) {
  for( int j = 0; j < 9; j++ ) {
    ellipse( 50 + j * 50, 50 + i * 50, 40, 40 );
  }
}

繰返しの回数は、同じ数を縦横に繰り返すのであれば、2箇所に指定があるので、変数にした方が良いのはもちろんですが、それ以外も以下のように書き換えてみます。

size( 500, 500 );
background( 255 );
smooth();

int repeatNum = 9;    //繰返しの回数
int circlePitch = 50; //円の間隔
int circleSize = 40;  //円の直径

int pitchWidth = circlePitch * ( repeatNum - 1 );
int leftX = ( width - pitchWidth ) / 2;  //余白

stroke( #339933 );
noFill();

for( int i = 0; i < repeatNum; i++ ) {
  for( int j = 0; j < repeatNum; j++ ) {
    int drawPointX = leftX + j * circlePitch;
    int drawPointY = leftX + i * circlePitch;
    ellipse( drawPointX, drawPointY, circleSize, circleSize );
  }
}

5〜7行目、繰返しの回数、円の間隔(隣り合う円の中心間の距離)、円の大きさをそれぞれ変数にし、9、10行目で複数の円が描かれる範囲と周囲の余白の値を求めています(余白と書きましたが、描画範囲をより円が描かれる範囲が大きい場合には、描画範囲をどれだけはみ出すかという値になります)。

17、18行目は、x座標とy座標の値を一端変数に代入しています。

このように書いて、以下、repeatNum、circlePitch、circleRadiusの値を色々と変えてみます。

円を縦横に並べる1
repeatNum = 5 circlePitch = 10 circleSize = 200

円を縦横に並べる2
repeatNum = 10 circlePitch = 20 circleSize = 200

円を縦横に並べる3
repeatNum = 10 circlePitch = 50 circleSize = 200

繰返しの回数、円の間隔、円の大きさを変えただけで、描画処理そのものは変えていませんが、一見、同じ描画処理とは思えない差が生まれます。

この辺りまでくると、描画処理を作る、つまりヴィジュアルの作り方を作るということの雰囲気や楽しさの一端が味わえるのではないでしょうか。

ページの先頭へ↑

< 10. ランダム

12. 関数で処理をまとめる >