メソッドの利用

メソッドは 名前(<値のリスト>) の形式で、一つの文で各種の処理を実行する機能です。println() も一種のメソッドです。メソッドは定義されたものを利用するだけでなく、自分で定義することも可能です。
 ここでは、メソッドの利用や定義の方法を紹介します。


  1. メソッドとは

     「メソッド」は「手法」の意味ですが、プログラミング言語によっては「関数」とも呼ばれます。processing でも多くの数学関数が利用できます。たとえば、平方根(square root)の値は次のように求めることができます。
     double r = sqrt(2.0); //平方根
     double r = power (3.2,3); //べき乗
     sqrt がメソッドの名前で () 内の 2.0 を引数と呼びます。この場合 2.0 の平方根がメソッドの「返す値」となります。メソッドの実行はメソッドの「呼び出し」とも言います。Processing では calculation(計算:17種)、trigonometry(三角関数:9種)、などの分野で多くのメソッドが用意されています。こんなメソッドもあります。
      int y = constrain( val, min,max); //val の値を minとmaxの間に制限する
      foat n = norm(val,min,max); //minとmaxの範囲の値であるvalを、0と1の間の範囲の数に変換(正規化)する。
      float n = map (va,min,max,Min,Max); //minとmaxの範囲の値であるvalを MinとMaxの範囲の数に変換(map)する
     メソッドは数学的関数だけでなく、グラフィック、音、ネットワーク、通信、などメディア関連のいろいろな機能を提供してくれます。println() もメソッドの仲間です。

  2. モードとメソッドの定義

    processing には static と active の2種があります。メソッドを新しく定義せずに、式の計算や定義済みのメソッドを利用するだけの場合、static モードになります。メソッドは自分で定義する場合 active モードとなり、定義したいメソッド以外に、setup というメソッドも定義する必要があります。関数の呼び出しは setup() 関数の中で行う必要があります。たとえば、
      f(x) = x 2 + 2.0 * x + 3.0
    のような数学関数をメソッドで定義します。
    //関数の定義
    double f(double x){
      return x*x + 2.0*x + 3.0;
    }
    
    void setup(){
      println(f(2.0));
    }
    ///11.0
    
     関数 f() が定義されば、f(2)で x=2 の値(この場合11)を得ることができます。setup() 関数は Processing が active モードで実行するときに最初に一度だけ実行する関数で、先頭の void はこの関数は何も値を返さないことを意味します。setup()を定義しないで、いきなり、自作の関数を呼び出すと次のエラー(activeとstaticモードの混同利用)がでます。
    //エラーになる
     println(f(2.0));
     
    //関数の定義
    double f(double x){
      return x*x + 2.0*x + 3.0;
    }
    ///It looks like you're mixing "active" and "static" modes.

  3. メソッドの型と引数

     先の例の double f(double x) で、先頭の double がメソッドが戻す値の型を、( )の中のdouble x が「引数」とその型を定めています。メソッドの呼び出しは一般に以下の形式になります。
     変数 = メソッド名(<引数>);
     メソッドで戻す値は、左辺の変数に渡されます。また、メソッドを呼び出すとき「引数」により処理に必要なデータを渡すことができます。メソッドの型が void である場合、あるいは、値を受け取る必要がないばあい ”変数 =” は省略できます。
     メソッドの引数で定義された変数はそのメソッド内部のみで利用できる変数になり、メソッド呼び出し時に値が渡されます。下の例で、setup() で引数に x の値を渡していますが、メソッド側では、別の変数 x に値を受け取り x=1 としています。この x は setup() 内部で定義された x とは別物ですから、println() で表示される値は 0 のままです。
    void setup(){
      int x=0;
      f(x);
      println(x);
    }
     
    //関数の定義
    void f(int x){
      x=1;
    }
    ///結果
    0

  4. 局所変数と広域変数

     メソッド内部で定義される変数(引数)は「局所変数」と呼ばれ、そのメソッド内部でのみ有効であり、メソッドの外部では利用できません。メソッド外部で定義される変数は「広域変数」と呼ばれ、メソッドで共通に利用できます。下の例で、y は「広域変数」になり、setup() でも f() でも共通に利用されます。したがって、f() で変更した y の値を setup() で表示することになります。
    int y=0;
    
    void setup(){
      int x=0;
      y=0;
      f(x);
      println(y);
    }
     
    //関数の定義
    void f(int x){
      x=1; y=1; //y は広域変数
    }
    ///結果
    1
     小さなプログラムでは広域変数で定義する方が便利そうですが、大きなプログラムになると「どこかのメソッドで勝手に変数の値が変更されてしまう」事態になりかねません。また、特定のメソッドだけで利用する変数を広域変数にすると広域変数の数が多くなり、プログラムがわかりにくくなります。
     局所変数の有効範囲は、正確にはブロック { } の内部に限定されます。下のプログラムで、先頭の for で定義された変数 i は当該ブロックでは利用可能ですが、次のブロックでは無効となり利用できません。
    void setup(){
      for(int i=0;i<10;i++){  
      }
      for(i=0;i<10;i++){
      }
    }
    ///cannot find anything named "i" 
     
  5. メモリの割り当てとゴミ集め 
     あるブロック(メソッド)で宣言された変数(もの)は、その「内部のみで利用される」原則は名前の重複利用を避ける意味もありますが、記憶領域(メモリー)の有効利用にもなります。ある関数内部で利用された大きな配列はそのメソッドが終了すると利用できなくなりますが、逆に考えるとその配列が利用していたメモリーを再利用できることになります。
     Processingでは使用可能な記憶領域が不足すると、再利用可能な記憶領域を集めて新たに必要となった記憶領域に割り当てる操作を行います。これを「ゴミ集め(Gabbage Collection:GC)」といいます。GC が実行されると処理が遅くなる問題もありますが、プログラムで開放する手間を省くことができます。

  6. 配列を引数にする

     先に、メソッドで受け取った引数の値を変更しても、呼び出した側の変数は変化しない、と説明しましたが、引数として配列を渡すと事情が異なります。下の例で、ary[] は setup() の「局所変数」ですが、メソッド f() で ary[] の値を変更すると、setup() で表示する値も変化します。
    void setup(){
      int[] ary={5,10,7};
      f(ary);
      println(ary[0]);
    }
    
    void f(int[] ary){
      ary[0]=0;
    }
     この違いは、メソッドへの渡し方にあります。整数や配列などは、計算機のメモリー中である場所(メモリーの「番地」とも言います)が割り当てられます。整数や少数など「単純変数(newで生成しない)」は、その「値」を渡しますが、配列など一般に new を利用して生成する「もの」は、「もの」のある「場所」を渡します。
     f() で 渡された ary[] 全体の「場所」から、0 番目の要素の「場所」をしらべ、そこの「値」を変更します。単純変数の場合、変数の「場所」ではなくその「値」を渡すので、メソッド側では(「単純変数」の場所がわからないので)渡された変数の値を変更できません。
  7. draw()メソッド

     Processingは setup() とdraw()メソッドが標準で用意されています。draw() は画面に描画を行うメソッドで、定期的に呼び出され画面を描きなおすことができます。画面の大きさは size(幅,高さ)で、 画面の背景は background(0..255の明るさ)で指定できます。また、frameRate(数字); で秒あたりの描きなおす回数を設定できます。
     下の例のdraw() で background(250);で背景色で塗りつぶし、ellipse(中心座標x,中心座標y、幅、高さ)で楕円を描きます。フレームごとに、直径 dia を inc の量だけ増減します。inc は幅を超えるか、20より小さくなると符号を替えて増減の方向を逆転します。
    int dia;
    int inc;
    void setup(){
      size(150,150);//画面のサイズ
      frameRate(20);//秒あたりのフレーム数
      dia=50;
      inc=2;
    }
    
    void draw(){
      background(250);//背景色で塗る
      //中心から 直径diaの円を描く
      ellipse(width/2,height/2,dia,dia);
      //直径を変更
      dia=dia+inc; 
      //幅より大きいか、10以下なら反転 
      if(dia>width || dia<10) inc=-inc;
    }
    実行画面


  8. イベント処理メソッド(マウス)

     ここでは、「イベント」とはマウスやキーボードなどの操作を言います。マウスやキーボードなどが操作されると OS(Windows や MACOS の意味です)はそれを感知し、現在アクティブになっているウインドウのアプリに「イベント情報」を伝えます。Processing では、「イベント」が通知されるとイベントに対応するメソッドを呼び出します。これらのメソッドは draw() メソッドを経由して呼び出されるので、draw() メソッドを定義しておく必要があります。
     下のプログラムは、マウスがクリックされた位置に円を描きます。マウスのボタンが押されるとmousePressed()メソッドが呼び出されます。マウスの位置は mouseX と mouseY に記録されているので、これを px,py に記録します。draw()メソッドでは、(px,py) の位置に直径 10 の円を描きます。background() メソッドを呼び出さないと描画した円は消えません。
    int px,py;
    
    void setup(){
      size(150,150);
      px=width/2;//初期値
      py=height/2;
    }
    
    void draw(){
      //background(200);
      ellipse(px,py,10,10);//円を描く
    }
    
    void mousePressed(){
      //マウスボタンが押された
      px=mouseX;//マウスのx座標
      py=mouseY;
    }
    実行画面

     マウス関連のイベント処理メソッドは他に、以下のようなメソッドがあります。
     mouseReleased():マウスボタンが離れた
     mouseMoved():マウスが移動した
     mouseDragged():マウスボタンを押したまま移動した
     
  9. イベント処理メソッド(キーボード)

     キーボードが押されると keyPressed()メソッドが呼ばれ、押されたキーの文字が変数 key に記録されます。キーが BACKSPACE, TAB, ENTER, RETURN, ESC, DELETE など「文字でない」場合、keyCode 変数に 対応する値で記録されます。
     下のプログラムでは方向キーで円が移動し、r と bキーで円の色が赤と黒に変化します。
    int px,py;
    
    void setup(){
      size(150,150);
      px=width/2;//初期値
      py=height/2;
    }
    
    void draw(){
      background(200);
      ellipse(px,py,10,10);
    }
    
    void keyPressed(){
      //キーが押された
      if (key == CODED){
        if(keyCode == UP)    py = py - 10;
        if(keyCode == DOWN)  py = py + 10;
        if(keyCode == LEFT)  px = px - 10;
        if(keyCode == RIGHT) px = px + 10;
      }
      if(key == 'r') fill(255,128,0);
      if(key == 'b') fill(0,0,0);
    }
    実行画面


  10. まとめ

     特定の機能をメソッドを定義することで、プログラムを機能単位に分割して記述でき、プログラムの見やすさや管理が容易になります。この、プログラム分割の概念をさらに拡張したものが、別項で紹介する「クラス」になります。