見出し画像

高校数学をプログラミングで解く(準備編)「4-1 図形を動かす」

マガジンリスト > 準備編 4.動画、3次元表示 > 4-1 図形を動かす


はじめに

これまで描いてきた図形はすべて動かない静止した図形でしたが、今回はその図形を動かすことを考えていきます。図形を動かすためには、draw 関数を利用する必要があります。ここでは、この draw 関数の利用方法について説明していきます。

図形を描くための関数

これまでのプログラムでは、setup 関数の中に必要な処理を書くことで、計算を行ったり、図形を描いたりしていました。でも、「setup」という名前の通り、本来は計算したり、図形を描いたりするための「設定」を行う関数です。本当は、計算したり図形を描いたりするための関数は draw 関数となります(「draw」は日本語で「描く」という意味ですね)。

点を描くプログラム

では、その draw 関数の扱い方について、点を描くプログラムを例にして説明していきます。
まず、setup 関数のみを用いたプログラムを作成してみます。

// 点を描くプログラム(setup関数のみを利用)
void setup(){
  size(400, 400);
  // キャンバスの中央に直径10ピクセルの点を描く
  strokeWeight(10);
  point(width/2.0, height/2.0);   
}

ソースコード1 点を描くプログラム( setup 関数のみ)

このソースコード1を、Processingの開発環境ウィンドウを開いて(スケッチ名を「plotPoint1」としています)、テキストエディタ部分に書いて実行すると、図1のように実行ウィンドウのキャンバスの中央に点(黒色)が描かれます。

図1 スケッチ「plotPoint1」の実行結果

draw 関数を利用した点を描くプログラム

次に、ソースコード1の点を描くプログラムを draw 関数を利用したプログラムに書き換えます。

// 点を描くプログラム(draw関数を利用)
void setup(){
  size(400, 400);
}

void draw(){
  // キャンバスの中央に直径10ピクセルの点を描く
  strokeWeight(10);
  point(width/2.0, height/2.0);   
}

ソースコード2 点を描くプログラム( draw 関数を利用)

ソースコード1と比較すると、ソースコード2では draw 関数を準備した上で、ソースコード1の setup 関数の中身の

  // キャンバスの中央に直径10ピクセルの点を描く
  strokeWeight(10);
  point(width/2.0, height/2.0);   

を draw 関数の方に移動させています。つまり、size 関数のような「設定」に関わる部分を setup 関数内に記述し、point 関数のような「描く」ことに関わるものを draw 関数に記述しています。

このソースコード2を、Processingの開発環境ウィンドウを開いて(スケッチ名を「plotPoint2」としています)、テキストエディタ部分に書いて実行すると、図2のように実行ウィンドウのキャンバスの中央に点(黒色)が描かれます。

図2 スケッチ「plotPoint2」の実行結果

図1と図2は全く同じ結果となっています。つまり、スケッチ「plotPoint1」(ソースコード1)とスケッチ「plotPoint2」(ソースコード2)のどちらでも点を描くために利用できます。ただ、Processingでは、ソースコード2のように、「設定」部分と「描く」部分を分けて考えることが本来求められる書き方となっているようです。

setup 関数と draw 関数の違いについて

では、setup 関数のみで図形を描くことと draw 関数を利用して図形を描くことは何が違うのでしょうか。実は、setup 関数は最初に一度だけ呼び出されますが、draw 関数は draw 関数内に記載した処理を1秒間に60回呼び出して実行するという違いがあります。
つまり、スケッチ「plotPoint1」の実行結果の図1とスケッチ「plotPoint2」の実行結果の図2は同じ画像に見えますが、図1は一度だけ描いた点が表示されているのに対して、図2は1秒間に60回更新されて表示されています。同じ位置に点をプロットし続けているので、図1と図2の違いが見えないだけです。

図形を動かす

すでにお気づきと思いますが、draw 関数をうまく利用することで、図形を動かすことができます。もう少し正確に言えば、1秒間に60回、キャンバス上の画像を更新することで図形を動いているように表示することができます。

点を動かすプログラム

では、先ほど作成した点を描くプログラム(ソースコード2)を書き換えて、点を左から右に動かすプログラムを作成してみます。

// 点を左から右に動かすプログラム

float x = 0.0; // 点の位置座標のx成分

void setup(){
  size(400, 400);
}

void draw(){
  // 背景を更新
  background(204);
  // 直径10ピクセルの点を左から右に移動させる
  strokeWeight(10);
  point(x, height/2.0);
  x = x + 1.0;
}

ソースコード3 点を左から右に動かすプログラム

このソースコード3を、Processingの開発環境ウィンドウを開いて(スケッチ名を「movePoint」としています)、テキストエディタ部分に書いて実行すると、図3のようにキャンバスの中央を点(黒色)が左から右に動いていく動画が描かれます。

図3 点を左から右に動かす

プログラムの解説1「更新のために利用する変数」

draw 関数が draw 関数内に記載した処理を1秒間に60回呼び出して実行するという性質を利用して画像を更新することで動画を作成するわけですが、draw 関数内の処理は呼び出されるたびに何らかの変化をさせなければなりません。
たとえば、点を左から右に動かす場合、点の位置を表す座標の$${x}$$成分の値を、処理が呼び出されるたびに少しずつ大きくしていく必要があります。これを実現するために、ソースコード3では、点の位置を表す座標の$${x}$$成分の変数としてfloat型の変数 x を導入しています。そして、この変数の値を draw 関数内で更新することで点の位置を少しずつ右に動かしています。

  x = x + 1.0;

ただし、変数 x の定義位置には注意してください。この変数は draw 関数でのみ利用するので、draw 関数内で定義してもよいように思われますが、実際はこれでは正しく動きません。なぜなら、変数は初期化を行う必要があり、draw 関数が更新のたびに初期化を行ってしまうからです。つまり、結果として全く変数の値の更新が行われません。
そのため、変数 x はdraw関数の外、プログラムの最初に定義と初期化を行っています。この位置に記述することで、スコープの関係上、変数 x は draw 関数でも利用することができ、draw 関数内で正しく更新することができます。

プログラムの解説2「背景の更新」

draw 関数を用いて図形が動くように見せるためには、点の位置だけではなく、背景も更新する必要があります。背景の更新を行わなかった場合、過去に描かれた点が残像のようにそのまま残ってしまいます。そのため、背景色でキャンバスを塗りつぶすことで点を一旦削除したあと、点の位置を更新して再度点を描くということを繰り返していきます。この背景を更新する処理を draw 関数内の先頭に入れています。

  // 背景を更新
  background(204);

なお、この背景の更新を行わなかった場合、図4のように、点の残像が残り、あたかも直線を描いていくような動画になります。

図4 背景を更新しない場合

draw関数で静止画を作成するときの注意点

setup 関数のみで点を描いた場合の図1と draw 関数を利用して点を描いた場合の図2は全く同じ結果となっていると述べましたが、draw 関数の機能を考慮すると、図2の点は1秒間に60回のペースで何度も上書きされていますので、全く同じ結果とは言えません。
draw 関数を利用して静止画を描きたい場合は、

noLoop();

を setup 関数内に記述します。これにより、draw 関数は1回だけ実行されるようになります。実際に、点を描くプログラム(ソースコード2)に noLoop 関数を導入してみます。

// 点を描くプログラム(draw関数を利用)
void setup(){
  size(400, 400);
  noLoop();
}

void draw(){
  // キャンバスの中央に直径10ピクセルの点を描く
  strokeWeight(10);
  point(width/2.0, height/2.0);   
}

ソースコード3 点を描くプログラム( noLoop 関数を利用)

ソースコード3による実行結果は図2と見た目が変わりませんが、draw 関数は1回しか実行されていません。
点を描くプログラム(ソースコード2)に導入しただけではちょっとわかりにくいかもしれないので、もしもう少し noLoop 関数の効果を確かめたいのであれば、点を左から右に動かすプログラム(ソースコード3)に noLoop 関数を導入してみてください。draw 関数が1回しか実行されないので、左端に点が描かれてそのまま動かない画像が描かれます(図5)。

図5 点を左から右に動かすプログラムにnoLoopを導入した場合

まとめ

今回は、図形を動かすために必要となる draw 関数の利用方法について説明しました。
draw 関数は、draw 関数内に記載した処理を1秒間に60回呼び出して実行するということを行います。その draw 関数の機能を利用して、キャンバス上の画像を更新していくことで図形を動いているように表示することができます。
Processingにおいて図形を動かすことはあまり難しくないと感じられたのではないでしょうか。

参考文献

Processingをはじめよう 第2版(オライリー・ジャパン、オーム社、ISBN9784873117737)

この記事が気に入ったらサポートをしてみませんか?