たくさん覚える(配列)

2019-06-09

本章のあらすじ

  • 配列の概要とその生成方法
  • 配列でたくさん覚える
  • 配列とfor文との組み合わせ
作例:複数の点の位置を覚えておき、曲線で接続

変数の復習

配列を説明する前に、必須となる「変数」の復習をしておきましょう。

Processingでアニメーションを実現するには、位置や大きさなどの情報をどこかに覚えておく必要がある。変数は覚えておくためのもの、というお話でしたね。

復習:ランダムウォーク

変数」の章で作ったスケッチ、ランダムウォークを覚えていますか?ボールがランダムに移動(=ウォーク)していくスケッチです。変数の復習のためにもう一度作ってみましょう。

// 位置を覚えておくための変数
float ballX;
float ballY;

void setup() {
  size(600, 600);
  noStroke();
  fill(0);

  // ボールの初期位置の設定(変数の初期化)
  
}

void draw() {
  background(255, 255, 255);

  // ボールの移動(変数の更新)
  

  // ボールを描く
  
}

ボールが存在するためには位置を覚えておく必要があり、そのための変数が必要なのでした。 (→random_walk

ちなみに、こういった一定のルールにもとづいて移動するものを「エージェント」と呼びます。

練習:エージェントを増やしてみる

さて、先ほどのスケッチを土台に、このエージェントを2体に増やしたいとします。書けるでしょうか?

ヒント

  • エージェント1体を存在させるために、X座標・Y座標をそれぞれ覚えておく必要があり、2つの変数 ballX, ballY を用意していた
  • エージェントもう1体を存在させるためには…?

正解

正解は…エージェント2のための変数をもう1組用意します。

// エージェント1の位置を覚えておくための変数
float ballX1;
float ballY1;

// エージェント2の位置を覚えておくための変数
float ballX2;
float ballY2;

この調子で、初期化、移動、描画のすべてをエージェント2の変数に対しても適用すれば、2つのエージェントを存在させて動かすことができます。 (→random_walk_2

変数を増やすにも限界がある

同様の方法で、コードのコピペ・微修正を繰り返していけば、3つ4つとエージェントを増やしていけます。しかしこの作戦にはやがて限界がやってきます。10体くらいまでなら気合いと根性で何とかなる気もしますが、例えば10000体にしたいとなるともうお手上げですよね…。

たくさん覚えておきたいけど、一体どうやって実現すればよいのか?その解決策が今回のテーマ「配列」です。

配列

配列は、たくさんの変数が並んだ集まりです。

配列の宣言

配列も変数の一種で、宣言してはじめて使えるようになります。例えば float 型(小数)の配列を用意したければ、末尾に [] を付加した float[] が配列の型になります。

// float型の配列を宣言
float[] values;

配列は、宣言したままでは空っぽです。

いくつの要素を持つ配列にするかをあらかじめ決めたうえで、 new キーワードを使って作成します。

// 要素数 6 の配列を作成
values = new float[6];

これではじめて配列用の領域が確保されて、 6 個の float 型の変数が使えるようになりました。

何番目の要素か:インデックス

配列の要素は確保したぶんの数だけあるので、そのうちのどれを使うかをコードで教えてあげる必要があります。

「先頭から*番目の要素」という指示をすれば、どの要素を指しているか一意に定まりますね。これを「インデックス (index) 」と呼びます。要素を探すための索引のようなものです。

例:3番目の要素

インデックスは 配列の名前 [ インデックス ] という書きかたで指定します。

例:3番目の要素は values[3]

配列の名前の後ろに [ インデックス ] がつく以外は、普通の変数と同じように使えます。

// 配列の要素を使う例

// 3 番目の要素に代入
values[3] = 3.1416;

// 0 番目の要素をコンソールに出力
println(values[0]);

ひとつ気をつけてほしいのが、インデックスは 0 番目からはじまるということ。要素数 6 の配列を作成した場合、先頭のインデックスは 0 、末尾のインデックスは 5 になります。

練習:配列を使ってみる

先ほどのエージェント2体のスケッチを、配列を使って書き直してみましょう。

まず、 ballX1, ballX2, と変数名で区別していたエージェントの変数を配列でまとめます。配列は複数の要素を持っているので、わかりやすいように変数名に複数形の「s」をつけておきましょう。

// エージェントの位置を覚えておくための変数
float[] ballXs;
float[] ballYs;

配列は宣言しただけでは空っぽでしたね。長さを指定して new で作成しましょう。エージェントは2体なので、配列の長さは2でよいでしょう。

  // 配列の個数を決めて生成
  ballXs = new float[2];
  ballYs = new float[2];

あとは、 ballX1ballXs[0] に、 ballY1ballYs[0] に、…と配列を使うように書き換えていけば完了です。

  // エージェント1の変数の初期値(開始時の位置)をキャンバス中央に設定
  ballXs[0] = width / 2;
  ballYs[0] = height / 2;

エラーなく実行できたでしょうか? (→random_walk_array_2

これで配列を使うように書き直せましたが、現時点では普通に変数を宣言するのと大差ありません。ここからが配列の本領発揮です。

ループ変数とインデックス

[] 内のインデックスには数値を入れてきましたが、整数の変数( int 型)でも指定できます。

for文などのループ変数と組み合わせれば、一気に処理することが可能になります。例えば、すべてのエージェントの初期位置を画面中央に設定する以下のコード。

// エージェント1の変数の初期値(開始時の位置)をキャンバス中央に設定
ballXs[0] = width / 2;
ballYs[0] = height / 2;

// エージェント2の変数の初期値(開始時の位置)をキャンバス中央に設定
ballXs[1] = width / 2;
ballYs[1] = height / 2;

for文を使うと以下のように書き換えられます。

for (int i = 0; i < 2; i++) {
  // i 番目のエージェントの変数の初期値(開始時の位置)をキャンバス中央に設定
  ballXs[i] = width / 2;
  ballYs[i] = height / 2;
}

for文の挙動を脳内でシミュレートしながら、同じ実行結果になることを確認しましょう。デバッガーの力を借りるのもよいでしょう。

同様に、位置の更新・描画処理をfor文で書き直してみましょう。 (→random_walk_array_for

うまく動いたら、配列の要素数とfor文の終了条件の上限を増やしてみてください。コードをたくさんコピペしなくても、数値を書き換えるだけで大量のエージェントを生成することができるようになりました!

たくさんのものをアニメーションさせるには、そのぶんだけ覚えておく情報も増えていきます。配列とループ変数を組み合わせることで、膨大な数のデータの記憶や更新処理を簡潔に記述できるようになるのです。

練習:配列の理解を深める

for文を使った複数体エージェントのランダムウォーク(→random_walk_array_for)を改造して、配列の理解を深めましょう。

  • エージェントの数を増やしてみる。どこまでいけそう?
  • エージェントに色や大きさなどの個性を持たせられるだろうか?
  • エージェントに持たせた個性(色や大きさなど)を、時間経過で少しずつ変化させられるだろうか?

(→random_walk_array_colorful

本章のまとめ

  • 配列はたくさんの変数をまとめて生成できる
  • ループ変数と組み合わせると、たくさんのものを同時に動かしたり描いたりできる