配列を説明する前に、必須となる「変数」の復習をしておきましょう。
Processingでアニメーションを実現するには、位置や大きさなどの情報をどこかに覚えておく必要がある。変数は覚えておくためのもの、というお話でしたね。
「変数」の章で作ったスケッチ、ランダムウォークを覚えていますか?ボールがランダムに移動(=ウォーク)していくスケッチです。変数の復習のためにもう一度作ってみましょう。
// 位置を覚えておくための変数
float ballX;
float ballY;
void setup() {
size(600, 600);
noStroke();
fill(0);
// ボールの初期位置の設定(変数の初期化)
…
}
void draw() {
background(255, 255, 255);
// ボールの移動(変数の更新)
…
// ボールを描く
…
}
ボールが存在するためには位置を覚えておく必要があり、そのための変数が必要なのでした。
(→random_walk
)
ちなみに、こういった一定のルールにもとづいて移動するものを「エージェント」と呼びます。
さて、先ほどのスケッチを土台に、このエージェントを2体に増やしたいとします。書けるでしょうか?
ballX
, ballY
を用意していた正解は…エージェント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 番目の要素に代入
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];
あとは、 ballX1
を ballXs[0]
に、 ballY1
を ballYs[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
)を改造して、配列の理解を深めましょう。