コンピュータプログラミングII (4)

処理のまとまりをつくる (1)

このスライドの使い方

テキスト等がはみ出した場合は、フォントサイズを小さくして調整する。 「S」 キーで小さく、「B」 キーで大きくなる。また、 下記のキーボード操作が使用できる。(一部キー操作は IE のみ対応)

「←」 or 「Page Up」 前のスライドに戻る
「→」 or 「Page Down」 or「スペース」 次のスライドに進む
「Home」 and 「End」 先頭(Home)または最後(End)のスライドへ移動
「C」 or 「contents?」 をクリック スライド一覧の表示
「F11」 or 「Ctrl+Shift+F (Win)」, 「Cmd+Shift+F (Mac)」 フルスクリーン表示と通常表示の切り替え
「F」 フッタの表示と非表示の切り替え
「A」 全スライド表示に切替 (印刷時に使う)
「S」「-」/「B」「+」 フォントサイズの大(B) 小(S)

本日のゴール

関数

関数(function): ある機能を実現する処理のまとまり。

復習: Processing に用意された関数

Processing には、あらかじめ用意された様々な組み込み関数(built-in function)がある。

http://processing.org/reference/

関数の名前を関数名と呼ぶ。

関数の利用

関数を使うことを、 関数の呼び出し(call) あるいは実行(execution)とも呼ぶことがある。

関数の利用

関数名(引数1, 引数2, ...);
// 例
ellipse(a, b, c, d);

関数の利用の例

組み込み関数を使うときには リファレンスマニュアル http://processing.org/reference/ を参照し、引数の数、各引数の意味と型を確認する。

例: ellipse()

戻り値も確認する必要があるが、これは次週に。

復習: 決まったタイミングで実行される組み込み関数

これまでにも、 決まったタイミングで実行される組み込み関数については、 関数の中身を自分で決めてきた。

void setup() {
  // ここに処理を書く


}

独自の関数の作り方

void 関数名() {
  // ここに処理を書く

}

独自の関数の作り方 - 例1

複数の円を描くプログラム

独自の関数の作り方 - 例1

円を描く元のプログラム

final int N = 10;                // 円の個数

size(400, 400);                  // ウィンドウのサイズ
background(255, 255, 255);       // 背景色(白)
noStroke();                      // 輪郭線を無効に
colorMode(HSB, 360, 100, 100);   // カラーモードをHSBに

for (int i = 0; i < N; i++) {
  fill(random(0, 360), 60, 100);            // ランダムな色相 (カラーモードはHSB)
  float d = random(50, 300);
  float r = d / 2;
  ellipse(random(r, width - r), random(r, height - r), d, d);   // 円
}

独自の関数の作り方 - 例1

setup 関数の導入

final int N = 10;                  // 円の個数

void setup() {
  size(400, 400);                  // ウィンドウのサイズ
  background(255, 255, 255);       // 背景色(白)
  noStroke();                      // 輪郭線を無効に
  colorMode(HSB, 360, 100, 100);   // カラーモードをHSBに

  for (int i = 0; i < N; i++) {
    fill(random(0, 360), 60, 100);            // ランダムな色相 (カラーモードはHSB)
    float d = random(50, 300);
    float r = d / 2;
    ellipse(random(r, width - r), random(r, height - r), d, d);   // 円
  }
}

processing のモード

static mode

active mode

active mode における関数を書く位置

関数の定義は同じ階層に並べて書く。

(例は次のスライド)

独自の関数の作り方 - 例1

関数 drawCircle の作成

final int N = 10;                  // 円の個数

void setup() {
  size(400, 400);                  // ウィンドウのサイズ
  background(255, 255, 255);       // 背景色(白)
  noStroke();                      // 輪郭線を無効に
  colorMode(HSB, 360, 100, 100);   // カラーモードをHSBに

  for (int i = 0; i < N; i++) {
    drawCircle();                  // 円の描画
  }
}


/** 円を描く(直径・色相はランダム) */
void drawCircle() {
  fill(random(0, 360), 60, 100);            // ランダムな色相 (カラーモードはHSB)
  float d = random(50, 300);
  float r = d / 2;
  ellipse(random(r, width - r), random(r, height - r), d, d);   // 円
}

独自の関数の作り方 - 例2

独自の関数の作り方 - 例2

/** 人の形を描く(色相はランダム) */
void drawHuman() {
  fill(random(0, 360), 100, 100);            // ランダムな色相 (カラーモードはHSB)
  ellipse(x, y - bodyHeight, faceDiameter, faceDiameter);               // 顔
  rect(x - bodyWidth / 2, y - bodyHeight, bodyWidth, bodyHeight);       // 胴体
}

独自の関数の使い方 - 例2

int x = 50;                        // 人のx座標の初期値
int dx = 50;                       // 人の間隔
int y = 300;                       // 人の列のy座標
int bodyWidth = 20;                // 体の幅
int faceDiameter = 30;             // 顔の直径
int bodyHeight = 160;              // 胴体の長さ
int n = 7;                         // 人数

void setup() {
  size(400, 400);                  // ウィンドウのサイズ
  background(255, 255, 255);       // 背景色(白)
  noStroke();                      // 輪郭線を無効に
  colorMode(HSB, 360, 100, 100);   // カラーモードをHSBに

  for(int i = 0; i < n; i++) {
    drawHuman();                   // 人の描画
    x = x + dx;
  }
}

練習1: 人が3列に並んでいる様子

練習1: 人が3列に並んでいる様子

前準備

int x;                      // 人のx座標
int ix = 50;                // 人のx座標の初期値
int dix = -10;              // 人のx座標の差分
int dx = 50;                // 人の間隔
int y = 200;                // 人の列のy座標の初期値
int dy = 75;                // 人の列の間隔
int bodyWidth = 20;                 // 体の幅
int faceDiameter = 30;                 // 顔の直径
int bodyHeight = 160;                // 胴体の長さ
int n = 7;                  // 人数
int m = 3;                  // 列の数

練習1: 人が3列に並んでいる様子

void setup() {
  size(400, 400);                  // ウィンドウのサイズ
  background(255, 255, 255);       // 背景色(白)
  noStroke();                      // 輪郭線を無効に
  colorMode(HSB, 360, 100, 100);   // カラーモードをHSBに

  for(int i = 0; i < m; i++) {
    x = ix;
    for(int j = 0; j < n; j++) {
      drawHuman();                   // 人の描画
      x = x + dx;
    }
    ix = ix + dix;
    y = y + dy;
  }
}

/** 人の形を描く(色相はランダム) */
void drawHuman() {
  fill(random(0, 360), 100, 100);  // ランダムな色相 (カラーモードはHSB)
  ellipse(x, y - bodyHeight, faceDiameter, faceDiameter);         // 顔
  rect(x - bodyWidth / 2, y - bodyHeight, bodyWidth, bodyHeight);    // 胴体
}

変数とスコープ

変数の型宣言 (復習)

int a;
float b;
int[] c;

Processing では、変数を使う前であればどこでも型宣言が可能。

変数の型宣言とスコープ

変数のスコープ(有効範囲): 型宣言をしたブロック内

void setup() {
  int x = 10;      // 変数x は setup() 関数のブロック内のみ有効
  ...
}

変数とスコープ: ローカル変数

void setup() {
  int x = 10;
  ...
}

void draw() {
  x = 20;            // x は setup() の中でしか有効ではないため、エラーとなる
}

変数とスコープ: グローバル変数

int x;

void setup() {
  x = 10;
  ...
}

void draw() {
  x = 20;            // x は setup() の中でも draw() の中でも有効
}

引数のある関数の作り方

void 関数名(引数1の型 引数1の変数名, 引数2の型 引数2の変数名, ...) {
  // ここに処理を書く

}

void drawHuman(int x, int y) {
  // ここに処理を書く

}

なお、組み込み関数と同じ名前で、引数の型もすべて同じ関数を定義した場合、自分で定義したものが優先される。

引数の受け渡し

void setup() {
  int humanX = 3, humanY = 2;
  drawHuman(humanX, humanY);
}

void drawHuman(int x, int y) {
  // x = humanXy = humanY が行われたのと同じ状態でスタート

}

引数の受け渡し

実引数の変数名と、仮引数の変数名が同じ場合

void setup() {
  int x = 3, y = 2;
  drawHuman(x, y);
}

void drawHuman(int x, int y) {
  // x = (setupの)xy = (setupの)y が行われたのと同じ状態でスタート

}

引数のある関数の例

/**
 *  人の形を描く(色相はランダム)
 *  @param x 人のx座標(体の中央軸)
 *  @param y 人のy座標(足元)
 */
void drawHuman(int x, int y) {
  fill(random(0, 360), 100, 100);  // ランダムな色相 (カラーモードはHSB)
  ellipse(x, y - bodyHeight, faceDiameter, faceDiameter);         // 顔
  rect(x - bodyWidth / 2, y - bodyHeight, bodyWidth, bodyHeight);    // 胴体
}

練習2: 身長の異なる人の列

練習2: 身長の異なる人の列

final int humanX0 = 50;                  // 人のx座標の初期値
final int dhumanX = 50;                  // 人の間隔
final int humanY0 = 300;                 // 人の列のy座標
final int humanBodyWidth = 20;           // 体の幅
final int faceDiameter = 30;             // 顔の直径
final int n = 7;                         // 人数

void setup() {
  size(400, 400);                  // ウィンドウのサイズ
  background(255, 255, 255);       // 背景色(白)
  noStroke();                      // 輪郭線を無効に
  colorMode(HSB, 360, 100, 100);   // カラーモードをHSBに

  int humanX = humanX0;
  for(int i = 0; i < n; i++) {
    int humanBodyHeight = (int)random(120, 160);            // 胴体の長さ
    drawHuman(humanX, humanY0, humanBodyHeight);            // 人の描画
    humanX = humanX + dhumanX;
  }
}

練習2: 身長の異なる人の列

/**
 *  人の形を描く(色相はランダム)
 *  @param x 人のx座標(体の中央軸)
 *  @param y 人のy座標(足元)
 *  @param bodyHeight 人の胴体の長さ
 */
void drawHuman(int x, int y, int bodyHeight) {
  fill(random(0, 360), 100, 100);                    // ランダムな色相 (カラーモードはHSB)
  ellipse(x, y - bodyHeight, faceDiameter, faceDiameter);                  // 顔
  rect(x - humanBodyWidth / 2, y - bodyHeight, humanBodyWidth, bodyHeight);    // 胴体
}

drawHuman() の仮引数 bodyHeight を ellipse(), rect() の引数として使っている。

引数の受け渡し: 配列の場合

void setup() {
  int[] p = new int[] {3, 2};
  drawHuman(p);
}

void drawHuman(int[] c) {
  // int[] c = p が行われたのと同じ状態でスタート

}

引数の受け渡し: 配列の場合

練習3: 正方形で描く円

練習3: 正方形で描く円

final float radius = 150.0;      // 円の半径
final float dTheta = 30;           // 回転角の増分
final float m = 100.0;           // 正方形の一辺の長さ

void setup() {
  size(400, 400);
  noStroke();
  background(255, 255, 255);
  colorMode(HSB, 360, 100, 100);  // 色の指定をHSBに
                                  // (色相 0-360, 彩度 0-100, 明度 0-100)

  for(float theta = 0; theta < 360; theta += dTheta) {
    float rad = radians(theta);   // 回転角
    float x = radius * cos(rad);
    float y = -radius * sin(rad);
    drawSquare(x + 200, y + 200, m, theta);  // 中心座標、辺の長さ、色相
  }
}

練習3: 正方形で描く円

/**
 *  正方形を描く
 *  @param x 中心のx座標
 *  @param y 中心のy座標
 *  @param m 1辺の長さ
 *  @param h 色相
 */
void drawSquare(float x, float y, float m, float h) {
  fill(h, 100, 100);
  rect(x - m / 2, y - m / 2, m, m);
}

rectMode()

rectMode(CENTER) とすると、左上ではなく中心の座標を指定して描画するモードになる。

  rect(x - m / 2, y - m / 2, m, m);
  rectMode(CENTER);      // rect の第1,第2引数を中心座標に
  rect(x, y, m, m);

上記2つは同じ意味。