覚えておく(変数)

2019-05-07

本章のあらすじ

  • 変数とは
  • 変数の使いかた
  • 変数の種類

アニメーション

アニメーション」の回では、 draw() ブロックの中で消しては描いてを繰り返すことで、ものの動きが表現できることを学びました。

毎回無に帰ってしまう世界にものを置きたい

Processingの世界では、 background() で背景を消去するとまっさらになってしまいます。

このような世界において、例えば「だんだん膨らんでいく風船」や「自由に動き回るボール」のようなものはどのように表現すればよいのでしょうか?

アニメーションとは少しずつ変化していくもの。大きさが変わるものであれば「先ほどまでどれくらいの大きさだったか」を、移動するものであれば「先ほどまでどの場所にいたか」を覚えておいて、少しずつ変えていく必要があるのです。

覚えておくための仕組み「変数」

つまり、ものを存在させて動かすためには、大きさや位置など、そのものに関する情報を覚えておく仕組みが必要なのです。

今回は、プログラミングの世界で覚えておくための仕組みである「変数」を学んでいきます。

例1:風船を膨らませる

シンプルな例として、クリックで膨らむ風船を作ってみましょう。

まずは draw() ブロック内で ellipse() を実行し、風船を画面中央に表示するスケッチを作成してください。

void setup() {
  size(600, 600);

  strokeWeight(2);
  fill(255, 200, 100);
}

void draw() {
  background(255, 255, 255);
  
  ellipse(300, 300, 200, 200);
}

マウスボタンを押したときのブロックは mousePressed() でしたね。

// マウスボタンを押したとき実行されるブロック
void mousePressed() {
  // ここで風船を膨らませたい
}

さて、この風船を膨らませるにはどうすればよいでしょうか?

クリックしたとき、風船の大きさを前より少し大きくすればよいのですが…いま手持ちの知識ではこれを実現する術がありません。

このスケッチを実現するためには、風船の大きさを何かしらの方法で覚えておく必要があります。

  1. 風船の大きさをどこかにメモしておく
  2. メモした大きさで円(風船)を描く
  3. クリックしたとき、メモしていた大きさを書き換えて、少し大きくする
  4. メモした大きさで円(風船)を描く
  5. …(以下繰り返し)

このメモしておく・覚えておくために必要なのが、今回のテーマ「変数」です。

変数とは

「変数 (variable) 」とは、値を覚えておける仕組みです。覚えた値は、取り出したり入れ直したりできます。

変数は値を覚えておける仕組み

そのままだと何の値かわからなくなってしまうので、変数には名前がつけられます。先の例では「風船の大きさ」に使いたいので、その目的がわかるような名前をつけておきたいですね。

変数には名前がつけられる…?

風船の大きさ用の変数を作る

変数を新たに作成することを「宣言」といいます。風船の大きさ用の変数を宣言するには、以下のように文を書きます。

float 変数名 ;

変数の名前は、Processingが用意しているキーワードと被らなければ基本的には何でもOKです1。意味が理解しやすい名前をつけましょう。

// bsize という名前で変数を宣言
// 風船 (balloon) の大きさ (size) に使うので
float bsize;

void setup() {
  size(600, 600);
  
}
変数にはわかりやすい名前をつける(なくさないように)

これで、 bsize という名前で数値の変数が使えるようになりました。

変数を利用する

宣言した変数は、これまで出てきた mouseXframeCount などと同じく数値のように扱え、計算式に組み入れることもできます。

void draw() {
  // 変数 bsize を大きさとして円を描く
  ellipse(300, 300, bsize, bsize);
}

さて、このままスケッチを実行しても何も表示されません。というのも、変数 bsize は宣言するのみでは空っぽのままです。覚えておく準備ができたら、中身に数値を入れていきましょう。

変数に値を入れる

変数に値を入れることを「代入」といい、等号 = を使って文を書きます。

// 変数 bsize に 100 を入れる
bsize = 100;

少しややこしいのですが、慣れ親しんだ等号を使うものの「等しい」という意味はなく別物2です。「= の右側にあるものを左側にコピーする」という意味であることを意識しましょう。

本筋に戻って、風船の最初の大きさ(初期値)を設定しましょう。初期値を設定するのはプログラム開始直後の最初の1回だけでよいので、 setup() ブロックが適していますね。

// 最初の1回だけ実行されるブロック
void setup() {
  size(600, 600);

  // 変数 bsize に 100 を入れる
  // 風船の最初の大きさは 100
  bsize = 100;
}

無事に風船は表示されましたか?

風船を大きくする

さて、ようやくここから変数が活きてくるところです。

これまで書いたコードによって、風船は変数 bsize にもとづいて描かれるようになりました。つまり、 bsize の数値を大きくすれば風船も大きくなるはずです。

マウスボタンを押したときに実行されるブロック mousePressed() で、 bsize の数値を大きくしましょう。

void mousePressed() {
  bsize = bsize + 10;
}

= を「等しい」と読んでしまうと何だか奇妙な式に見えてしまいますが… = は「代入」、右側の計算結果を左側に入れるという意味でしたね。つまりこの場合、「 bsize10 足した結果を bsize に入れ直す(再代入する)」という意味になります。

足してから入れ直す

ここまで書けたら実行してみてください。クリックするたびに風船が大きくなるスケッチができました! (→mouse_balloon

発展:さらに高みを目指す人へ

  • サイズを色や太さにも反映してみよう
  • もし大きくなりすぎたら、また0からスタートさせられるだろうか?(ヒント:if文)
  • 何もしないと自動的にしぼませることはできるだろうか?

例2:ボールを動かす

もう少し複雑な例で練習してみましょう。キーボードの方向キーでボールを動かすスケッチを作ってみます。

まずは円でボールを描くところまで準備しましょう。

void setup() {
  size(600, 600);
  
  strokeWeight(2);
  fill(100, 200, 255);
}

void draw() {
  background(255, 255, 255);
  
  ellipse(300, 300, 50, 50);
}

複雑なプログラムを作るときは、このようにもっともシンプルな形から作りはじめて、目指す形に向けて少しずつ機能を足していきます。焦らず一歩ずつ、着実に進めていきましょう。

ボールの位置に使う変数を宣言する

今回の例ではボールが移動します。ボールが移動するためには、その位置を覚えて維持する必要がありますね。ボールの位置(X座標、Y座標)をそれぞれ変数にしましょう。

// ボールの位置として使う変数を宣言する
float ballx;
float bally;

変数を初期化する

宣言するだけでは変数たちは空っぽなので、 setup() ブロックで初期化してボールの初期位置を決めましょう。キャンバスの中央がよいので、サイズ 600 の半分にしましょうか。

void setup() {
  size(600, 600);

  strokeWeight(2);
  fill(100, 200, 255);

  // それぞれに 300 を代入して初期化
  ballx = 600 / 2;
  bally = 600 / 2;
}

変数を位置に反映する

ボールの位置が固定のままなので、変数にもとづいた位置に描かれるようにしましょう。円の中心座標を ballx, bally にすればよいですね。

void draw() {
  
  
  ellipse(ballx, bally, 50, 50);
}

キーを押したとき: keyPressed() ブロック

マウスボタンを押したときに実行されるブロック mousePressed() があるように、キーを押したときに実行されるブロック keyPressed() も用意されています。

// キーを押したときに実行されるブロック
void keyPressed() {
}

どのキーが押されたかは、 keyCode という特別なキーワードが用意されているのでこれを利用します。方向キーのキーコードはそれぞれ LEFT, RIGHT, UP, DOWN となります。これらをif文で比較すれば、特定のキーを押しているかどうかで処理を分岐できます。

// キーを押したときに実行されるブロック
void keyPressed() {
  // 押しているキーが左方向キーのとき
  if (keyCode == LEFT) {
    
  }
  // 押しているキーが右方向キーのとき
  else if (keyCode == RIGHT) {
    
  }
}

変数の値を更新する

現状では、変数は初期値のままなのでボールは動きません。先ほど書きかけた keyPressed の中身を埋めて、 ballx, bally の値を更新してみましょう。答えを見ずに埋められるかチャレンジしてみてください。

void keyPressed() {
  // もし押したキーが左矢印( LEFT )のとき
  if (keyCode == LEFT) {
    // ボールの位置として使っている変数 ballx を 10 減らす
    ballx = ballx - 10;
  }
  // もし押したキーが右矢印( RIGHT )のとき
  else if (keyCode == RIGHT) {
    // ボールの位置として使っている変数 ballx を 10 増やす
    ballx = ballx + 10;
  }
  // もし押したキーが上矢印のとき
  
}

無事に動いたでしょうか? (→key_ball

発展

  • クリックしたとき、位置をリセットして中央に戻せるだろうか?
  • 例1を組み合わせて、動くたびに大きくなるボールは作れるだろうか?
  • ウィンドウ端を超えないようにできるだろうか?

変数について詳しく

変数について、もう少し一般的な話をしておきましょう。

変数を宣言する際、これまではおまじないのように float と書いてきました。

float 変数名 ;

この float 、実は変数の種類(「」と呼ぶ)を表しており、「この変数は小数です」という意味を持っています。Processingの世界では、変数に入るものの種類はあらかじめ決めておく必要があるのです。

変数には種類(型)がある

本来、変数の宣言文は以下のような構造になっています。

変数の型 変数名 ;

Processingにおける変数の型

Processingの公式リファレンス(Data→Primitive)によると、基本的な型は全部で8種類。ここではよく利用する4種類を紹介します。

意味
float 数値(小数) 3.1416, 100.0
int 数値(整数) 100
boolean 2値(ON/OFF) true, false
color #0088ff, #7890ab

小数: float

今回、風船の大きさやボールの位置に利用してきた float は小数です3。位置や大きさに関するほとんどのものはこれでまかなえるので、もっともよくお世話になる型になるでしょう。

float bsize;



void setup() {
  bsize = 3.14;
  
  // 整数を入れているように見えるが、内部的に 100.0… に変換されている
  bsize = 100;

  
}

整数: int

個数や回数など、端数が発生すべきでない場面では、整数用の int を利用します。詳細については、後ほどの章で出てくるのでそのときに解説します。

int count;



void setup() {
  count = 20;

  
}

ブーリアン: boolean

照明のスイッチやモード切り替えなど、ONとOFFの2通りしかない場合は boolean (ブーリアン4)が最適です。 true がON、 false がOFFを表します。

boolean light;
boolean sleepy;



void setup() {
  // ON
  light = true;
  
  // OFF
  sleepy = false;

  
}

色: color

Processingには、色を表現するための型も用意されています。 fill()stroke(), background() など、色を必要とするものに使えます。詳細については、また後日触れることにしましょう。

color col;



void setup() {
  // 赤色を代入
  // (Processingでは # からはじまる16進数表記を色として使える)
  col = #ff0000;
  
  // そのまま背景や塗りなどに設定できる
  background(col);
  fill(col);
  stroke(col);

  
}

変数のその他雑多なこと

宣言と初期化は同時に書ける

変数の宣言と初期化の代入は別々の文で書いていましたが、まとめて書くこともできます。

// 宣言
float hoge;

void setup() {
  

  // 代入
  hoge = 3.14;

  
}
// 宣言と同時に代入
float hoge = 3.14;

慣れてきたら使ってみるとよいでしょう。

実は変数だったものたち:システム変数

これまで、「Processingの特別なキーワード」として説明してきたものがいくつかありましたね。 () なしで数値と同様に扱えたものたち、例えば frameCount, mouseButton, mouseX, mouseY, keyCode, …。これらは実は変数なのです。

Processingが用意してくれた、宣言なしで使え、勝手に値が更新される特別な変数たち。これらを「システム変数 (system variable)」といいます。

上に挙げた以外にも複数ありますが、よく使う便利なものを紹介しておきましょう。

システム変数 意味
width int キャンバスの幅
height int キャンバスの高さ

変数の代入は値のコピー

変数の代入は値のコピーです。といってもよくわかりませんよね。ひとつ例をみてみましょう。

最後にクリックした地点から、現在のカーソル位置まで線を引くスケッチです。 (→line_preview

クリックした地点を覚えておくために変数を利用しています。

// クリックした位置を覚えておくための変数を宣言
int px;
int py;

void setup() {
  size(600, 600);
  stroke(0);
  fill(0);
}

// マウスを押したとき実行されるブロック
void mousePressed() {
  // カーソル位置を変数に代入
  px = mouseX;
  py = mouseY;
}

void draw() {
  background(255);

  // クリック位置に円を描く
  ellipse(px, py, 10, 10);

  // クリックした位置から現在のカーソル位置まで線を描く
  line(px, py, mouseX, mouseY);
}

mousePressed() ブロックでは、用意しておいた変数にカーソル位置 mouseX, mouseY を代入していますね。

void mousePressed() {
  // カーソル位置を変数に代入
  px = mouseX;
  py = mouseY;
}

例えばこの時点でのカーソル位置 mouseX123 だった場合、 px には 123 が代入されます。このとき数値はコピーされるので、あとでカーソル位置がどこに移動しようとも、変数の中身は変わりません。

px, py にはそのときクリックした位置の座標が保持されるので、 draw() ブロック内では最新のカーソル位置 mouseX, mouseY まで線を引けているのですね。

void draw() {
  

  // クリックした位置から現在のカーソル位置まで線を描く
  line(px, py, mouseX, mouseY);
}

練習

変数に慣れるために、さらにいくつかスケッチを作ってみましょう。

照明のON/OFF

クリックするたびに照明のON/OFFを切り替えるスケッチを作ってみましょう。

ヒント

  • まずはキャンバス中央に円を描く
  • 照明の状態を覚えておく変数をひとつ作る(ON/OFFなので boolean が最適)
  • 状態に応じて塗り色を変える(ONなら〜、OFFなら〜。if-else文ですね)
  • マウスをクリックしたとき、状態を切り替える(ONならOFFに、OFFならONに。if-else文を使います)

(→bool_light

ランダムウォーク

ランダムに動き回るボールを描いてみましょう。 draw() ブロックを実行するたびに、ボールのX/Y位置をランダムに増減することで実現できます。

ヒント

  • まずはキャンバス中央にボールを描く
  • ボールの位置を覚えておくための変数を作り、組み込む
  • 毎フレームごと(つまり draw() の中)で、位置の変数をランダムに増減させる

(→random_walk

発展

  • 色や大きさもランダムにできる?
  • もっと動きかたに個性を出せないだろうか?

複数のペンの切り替え

右クリックするたびに複数のペンを切り替えるスケッチを作ってみましょう。

ヒント

  • まずは1色のペンツールを作る(参考: mouseDragged()
  • ペンの種類を覚える変数をひとつ作る(ペンは複数種類あり、端数はいらないので int が最適)
  • ペンの種類に応じて線の色を変える( 0 なら〜、 1 なら〜)
  • 右クリックのとき、ペンの種類を切り替える(参考: mouseButton

(→multi_pen

発展

  • 消しゴムツールも追加できる?
  • サンプルのGIFのように、キャンバス右上に現在のモードを可視化できる?

変数のいいところ

ここまで説明してきたように、変数そのものはデータを覚えておくための仕組みですが、それ以外にもうれしい効果があります。

1. 計算結果を入れておくのに便利

変数に計算結果を入れておけば、何度も同じ計算をする必要がなくなります。計算自体が複雑だったり、ものすごい回数繰り返されたりする場合は、計算結果を再利用することで負荷軽減にもつながります。

ellipse(width / 2, height / 2, 300, 300);
ellipse(width / 2, height / 2, 200, 200);
ellipse(width / 2, height / 2, 100, 100);
// 変数に代入する際に計算するだけ
float centerX = width / 2;
float centerY = height / 2;

// 計算結果の再利用!
ellipse(centerX, centerY, 300, 300);
ellipse(centerX, centerY, 200, 200);
ellipse(centerX, centerY, 100, 100);

2. 数値に名前をつけると見やすくなる

変数は、データに名前をつけて意味づけできる仕組みと捉えることもできます。

わかりやすい名前をつけられれば、他の人や数ヵ月後の自分(≒他人)がコードを読むとき、どんな処理を書いているかを探る手がかりになります。

// 600 って何だっけ?なんで 2 で割ってるんだっけ?
ellipse(600 / 2, 600 / 2, 300, 300);
ellipse(600 / 2, 600 / 2, 200, 200);
ellipse(600 / 2, 600 / 2, 100, 100);
// 「center」って名前がついてるから、たぶんキャンバスの中央のことだな
float centerX = width / 2;
float centerY = height / 2;

ellipse(centerX, centerY, 300, 300);
ellipse(centerX, centerY, 200, 200);
ellipse(centerX, centerY, 100, 100);

本章のまとめ

  • 変数は覚えておくための仕組み
  • = は「等しい」ではなく「代入」
  • 変数には種類があり、小数、整数、ブーリアン、色はよく使う
  • 効果的に使えば、計算負荷を下げたりコードを読みやすくしてくれたりする

あとで学ぶこと


  1. 変数名については、「先頭が数字からはじまるものはNG」など細かなルールはありますが、慣れるまではエラーが出てから考えるくらいの心構えで大丈夫です。 [return]
  2. この = 記号には「代入演算子」という名前がついています。くどいようですが「等しい」という意味ではありません。 [return]
  3. より厳密には、コンピューターで小数を表現する方法は複数あり、 float は「単精度浮動小数点型」です。が、本筋ではないのでここでは触れません。 [return]
  4. true を「真」、 false を「偽」として「真偽値」という呼びかたもあります。 [return]