Processingで独自の関数(ユーザー定義関数)を作る



Processingでデザインやアートを生成していく中でellpseやrect、lineといった関数はProcessingが用意したのもなので、関数にパラメータを入れるだけで図形や線が描けましたが、これとは別に独自の関数(ユーザー定義関数)を作ることができます。

ユーザー定義関数は、関数としてプログラムをまとめておいて、あとで必要な時に関数を使ってその処理を利用するといった感じです。今まで使ってきたProcessingの関数もそうだったでしょう。
複雑なプログラムや何行かにわたり作成したキャラクターやアート、デザインをプログラムコードの中で何度も描くことがある場合は、関数として処理をまとめておいたほうが便利です。

まずは、関数を作成する際の基本の構文はこちら。

戻り値の型 関数名(引数の型 引数名, 引数の型 引数名, ...) {
  処理の内容
  return 返す値; //戻り値がある場合
}


戻り値がない場合は「void」、戻り値がある場合は戻り値のデータ型(intfloatなど)を記述します。
引数は関数に渡す値です。値のデータ型とその名前を記述します。
複数ある場合はカンマ区切りで記述します。
戻り値がある場合は「return」で値を返すようにします。


プログラムは上から読んでいきますが、draw()内で関数が呼び出されたらその関数が記述されている所までいき、関数の処理を実行してまた戻ります。

実際にサンプルコードで見ていきましょう。

戻り値がある関数


ただただ掛け算をする関数を作ってみました。

void setup() {
  size(300, 300);
  background(255);
  noLoop();
}
 
void draw() {
  int product = multiplication(5, 8);
  println(product);
}
 
int multiplication(int a, int b) {
  return a * b;
}



multiplication(掛け算)という関数を作成。
扱うデータ型はintで引数もintとして、2つの引数(int型でa, b)を渡して掛け算の関数でaとbを掛けて、その答えをreturnで返します。
multiplication(5, 8)で掛け算した答えをproduct(積)の変数に格納。プログラムが正しいか確認するためprintlnでエディタ下のコンソールに変数productの値を表示させて確認します。
5×8なので40とコンソールに表示されます。

続いては戻り値がなく、関数の処理だけ実行する関数を作ってみます。

戻り値がない関数


ちょっとした遊びとして、皆さんご存知のドラクエの定番モンスターを描いてみました。

Processingで描くスライム

void setup() {
  size(800, 600);
  background(#ffffff);
  smooth();
  noLoop();
}

void draw() {
  // slime(x座標, y座標, サイズ)
  slime(150, 110, 150); // 中サイズ
  slime(400, 300, 200); // 大サイズ
  slime(650, 450, 100); // 小サイズ
}


/*
 ドラクエのスライムを描画するユーザー定義関数
 * @param x スライムの基準点(頭のてっぺん)のX座標
 * @param y スライムの基準点(頭のてっぺん)のY座標
 * @param s スライムの高さ(全体の大きさのスケール)
*/
void slime(float x, float y, float s) { // 座標とスケールの引数を設定
  pushMatrix(); // 現在の座標系を保存
  translate(x, y); // 渡された数値で座標系の原点を移動

  // スケーリングファクターを計算
  // 元のコードのスライムの高さが 165 で、s をその基準としてスケールを決定
  float scaleFactor = s / 165.0;
  scale(scaleFactor); // 計算したスケールファクターを適用

  // スライム本体
  noStroke();
  fill(#3c8af7); // 青色
  beginShape();
  vertex(0, 0); // 頭のてっぺん
  bezierVertex(-10, 45, -50, 48, -50, 48);
  bezierVertex(-50, 48, -100, 55, -100, 110);
  bezierVertex(-100, 110, -100, 165, 0, 165); // スライムの底辺の中心
  bezierVertex(0, 165, 100, 165, 100, 110);
  bezierVertex(100, 110, 100, 50, 50, 48);
  bezierVertex(50, 48, 10, 48, 0, 0);
  endShape(CLOSE);

  // 左目
  fill(255); // 白目
  ellipse(-30, 90, 36, 36);
  fill(0); // 瞳
  ellipse(-30, 90, 20, 20);

  // 右目
  fill(255); // 白目
  ellipse(30, 90, 36, 36);
  fill(0); // 瞳
  ellipse(30, 90, 20, 20);

  // 口
  strokeWeight(10);
  stroke(0);
  noFill();
  bezier(-40, 125, -30, 140, 30, 140, 40, 125);

  popMatrix(); // 元の座標に戻す
}


slime関数の引数の値はスライムを描き始める座標とします。
わかりやすくfloat型で x と y の2つの引数を設定しておき、外部からx座標とy座標の値を渡すようにします。
slime関数の中のtranslate(x, y)の部分で渡された値が入り、座標を移動させてスライムを描いていきます。
また、3つ目の引数の s は、スライムの大きさ(スケール)の値を渡す引数になります。
スケーリングファクターを計算の部分で、対象となるもののスケール(尺度)を計算して、スケールを調整するようにしています。
pushMatrix()を使い、translateで移動させる前の座標(デフォルトなので 0, 0 の座標)を保存しておき、最後にpopMatrix()で元の座標に戻せば次に描くスライムが 0, 0 の座標からわかりやすく指定できるようになります。
スライム自体はbezier()bezierVertex()でベジェ曲線を描いて表現しています。

スライムを描く関数は作成しましたので、あとはdraw()の部分でslime関数を呼び出し、引数にx座標とy座標、またサイズの値を入れて、どんどん描いていくことができます。

複数行のコードを書かなくても、たった1行で関数を呼び出してあげるだけとなります。

以下、実行になります。

Processingで描くスライム



複雑なプログラムや複数行あるコードを、何度も書かないといけないことがある場合は、関数を作って処理をまとめておけば、後に描きたいことが少しのコードですんだり、値を変えて編集などをする際も手間がかかることがなくなります。

皆さんも遊びで独自の関数(ユーザー定義関数)を作ってみてください。