アリソンパリッシュによる
このチュートリアルでは、p5.jsを使った、ユーザー入力に応答するスケッチを作成する方法を学びます。
目次
ビルトインProcessing変数
前のチュートリアルでは、スケッチで変数を作成する方法を、スケッチをより柔軟なものにする方法として示しました。これはつまり、同じ値を何度も使用できるということです。Processingでは、定義せずに最初から使用できるビルトイン変数が提供されています。これらの変数は、通常はスケッチの外にある事柄に関する情報を与えてくれます。前のチュートリアルで見たframeCountもその1つです。
widthとheight
widthとheight変数は、スケッチの幅と高さに対応する値をつねに持っています(ピクセル単位)。これは通常、createCanvas()関数で指定した値と同じになります。
widthとheight変数は、キャンバスのサイズを考慮したスケッチが作成できるという点で有用です。たとえば以下の2つのスケッチでは、同じコードが並んでいますが、キャンバスのサイズが異なります(上が200 x 200で、下が400 x 400)。それにもかかわらず、スケッチウィンドウ(キャンバス)のちょうど1 / 3 の直径の円を描画します。
この関係性は、正方形でない長方形のスケッチの場合でも維持できます。
マウスの位置
Processingでは、現在のフレーム内でのマウスカーソのXとY座標を含んだ、特別な変数mouseXとmouseYが提供されます。draw()内のコードは何度も何度も繰り返し、高速で実行されていることを思い出してください。その頻度は1秒間に約60回です。p5.jsライブラリに含まれる記述済みのコードの中には、この関数を繰り返し呼び出すものがあります。そしてそのたびに、mouseXとmouseY変数を、画面上のマウスカーソルの現在位置に更新します。この2つの変数をいっしょに使用すると、マウスが移動する形式でのユーザー入力に応答するスケッチの作成が容易になります。
次のスケッチは、現在のマウス位置の下に円を描画する簡単な例です。
もちろん、mouseXとmouseYの使用は、何も描画する要素の位置の制御に限ったものではありません。次のスケッチでは、mouseX値を使ってストロークの幅を制御し、mouseY値を使って楕円のサイズを制御しています。
次のスケッチはProcessingの典型的なサンプルです。draw()内でマウスを追跡しながらbackground()への呼び出しを省略すると、初歩的な描画プログラムが出来上がります。
これは、経時的な変化を組み込み、基本的な仕組みを変えることで、より良いものにできます。
ifを使った条件による振る舞い
ユーザーからの入力を処理しているとき、いつのまにか、スケッチに2つまたはそれ以上の異なる振る舞いを持たせたいと思っている自分に気づくことがよくあります。ある状況ではある方法で振る舞わせ、別の状況ではまた別の方法で振る舞わせたい、と考えるわけです。
たとえば、ユーザーがマウスカーソルをスケッチの下半分に移動させたら矩形を表示したい場合を想像してください。これはつまり、もしマウス位置が高さの半分より大きければ、矩形を表示する(そうでなければ何も表示しない)ということです。
これを実現するには、スケッチの振る舞いに条件を付ける必要があります。条件とは、”そうであるかどうかを調べ、そうである場合にはそれをする”と言える方法です。JavaScriptには、この場合に適した特別なシンタックス、ifステートメントがあります。
次のスケッチはまさにこの課題を解決しています。
ここでは次の3行が新しいコードです。
if (mouseY > height / 2) {
rect(100, 100, 200, 200);
}
ifステートメントを模式で示すと、次のようになります。
if (expr) {
code-to-run
}
exprは関係式(後述します)で、code-to-runは1つまたはそれ以上のJavaScriptステートメントです(たとえば関数呼び出しやforループ、ifステートメントなど)。関係式がtrueに評価されると、code-to-runのステートメントが実行されます。そうでない場合には、ステートメントは実行されません。
関係式
関係式は、これまで見てきた式とよく似ており、次の構造を持ちます。
式 演算子 式
この演算子は両辺に式を必要とします。関係演算子とほかの演算子との違いは、関係演算子は別の値に評価するのではなく、2つの特別な値、trueかfalseのどちらかに評価する点です。関係式は、2つの値が互いにどういう関係にあるかを調べるために使用されます。具体的に言うと、ある値がほかの値よりも大きいかどうかや、2つの値が等しいかどうかを調べたい場合です。
よく使用される関係演算子には次のものがあります。
演算子 | 意味 |
---|---|
> | 左辺は右辺より大きい |
< | 左辺は右辺より小さい(未満) |
== | 左辺と右辺は等しい |
>= | 左辺は右辺以上 |
<= | 左辺は右辺以下 |
p5.jsエディタで次のステートメントを実行し、結果を確認してください。
console.log(15 > 10);
console.log((3 * 30) < (2 * 40));
console.log((3 + 5) * 2 == (10 + 6));
複数のif
コードのdraw()内には複数のifステートメントを置くことができます(実際には、forループ内や別のifステートメント内など、どこにでも記述できます)。次のスケッチは、マウスがスケッチの下半分にあれば矩形を描画し、右半分にあれば円を描画するサンプルです。
またifステートメントを別のifステートメントの中に埋め込むこともできます。次はその例で、マウスが画面の右側にありかつ下半分にある場合のみ、円を描画します。
マウスのクリック
Processingにはまた、mouseIsPressedという名前の特別なビルトイン変数があります。これは、ユーザーがマウスを押しつづけている場合に値trueを、そうでない場合には値falseを保持します。mouseIsPressedを使用すると、ユーザーがマウスボタンを押しているかどうかに応じて異なる事柄をスケッチに行わせることができます。
次のスケッチは、マウスボタンが押されている場合にのみ円を表示します。
そうでない場合には…
次の課題が与えられたとしましょう。「マウスがスケッチの上半分にあるときには、円をスケッチの上部に円を描画し、そうでない場合にはスケッチ下部に円を描画するスケッチを作成しなさい」
最初、次のようなものを作成されるかもしれません。
しかしこれでは不十分です。下の円は、上のifステートメント内の関係条件がtrueに評価しないときでも、表示されつづけています。この例は、ifステートメントの閉じる中かっこ( } )の後に置いたコードはどれも、ifステートメントが成功したかどうかに関係なく実行される、ということを示しています。
これは、ifステートメントを2つにすることで解決できます。1つはマウス位置が上半分にあるかどうかを調べ、もう1つはマウス位置が下半分にあるかどうかを調べます。
演習
2つめのifステートメントの演算子として、ただの>でなく、>=を使う理由は何だと思いますか?
これは動作しますが、まだ詰められることがあります。ある条件が満たされたときにはある振る舞いを実行し、その同じ条件が満たされないときには別の振る舞いを実行したい、というのは実際よくある状況です。最初のifステートメントの関係演算子の逆を意味する2つめのifステートメントを入力する手数を省くため、JavaScriptでは、ifステートメントの最後に追加できるelse節が提供されています。
if (expr) {
some-code
}
else {
some-other-code
}
exprはtrueかfalseに評価する式です(つまり関係式かmouseIsPressedのような変数)。この式がtrueに評価されると、some-codeのステートメントが実行され、そうでない場合には、some-other-codeが実行されます。
したがって上記サンプルは次のように書き直すことができます。
次の例は、マウスが押されていれば線を描画し、そうでなければ矩形を描画します。
1つ取り出す
forループの使用時、ある特定の繰り返し時だけ、ほかとは異なる振る舞いを実行したいことがよくあります。その場合ifステートメントが非常に役立ちます。forループ内でifステートメントを使って、ループ変数が特定の値がどうかを調べ、そうである場合にその異なる動作を実行します。
2つ以上:else if
わたしたちは二者択一の世界に生きているわけではないので、1つのifと1つのelseでは十分でないときもあります。if/elseの上記デモでは、マウスがスケッチの上半分にあるときに円をスケッチの上部に表示し、マウスがスケッチの下半分にあるときにはスケッチの下部に円を表示しました。しかし、同じようなスケッチではあるものの、画面を三分割したい場合はどうでしょう? つまりマウスが画面の上1/3にあるときにはそこに円を表示し、画面中央1/3にあるときにはそこに円を表示し、画面の下1/3にあるときにはそこに円を表示する、という場合です。
次の例は、テストする条件が相互排他的で3つある場合です。以下はその論理です。
- マウスが画面の上1/3にあるか?
- もしそうなら、そこに円を描画する。
- もしそうでないなら、「マウスは画面中央1/3にあるか」を聞く。
- もしそうなら、そこに円を描画する。
- もしそうでないなら、マウスは画面の下1/3にあることになるので、そこに円を描画する。
この論理をJavaScriptで表現する最も簡単な方法は、else if節を使う方法です。構造は次のように表せます。
if (test) {
statements
}
else if (test) {
statements
}
else {
statements
}
次の例は、else ifを使って上記を実装したスケッチです。
ifステートメントは、関係するelse if節をいくつでも持つことができます。else if節が1つのときでも、else節は必ずしも必要ではありません。
関係式を && と || で結び付ける
< や > のような演算子を使った関係式はブール値と呼ばれる特殊な値に評価されます。ブール値とはtrueかfalseのいずれかです。
ブール値とともに使用される特別な演算子に、&& と || があります。&&は”論理積”と呼ばれ、|| は”論理和”と呼ばれます。式をこれらの演算子で評価すると、結果の値はブール値になります。これらの演算子を使って関係式を結び付けると、より洗練された関係式が形成できます。
&& 演算子も || 演算子も、これまで見てきたJavaScript演算子と同じように機能します。これらには左右に式が必要です。&& 演算子は、左辺の式と右辺の式両方がtrueに評価される場合にのみtrueに、それ以外の場合はfalseに評価されます。|| 演算子は、いずれかの式がtrueに評価されるとtrueに評価され、両方の式がfalseの場合だけfalseに評価されます。
これらの演算子は、ほかの演算子で使ったconsole.log()でテストできます。たとえば、次の
console.log((6 > 5) && (7 > 6))
はtrueを表示します。一方、
console.log((6 > 5) && (10 < 9))
はfalseを出力します。
|| 演算子を使った次の上のコードの結果はtrueです(|| 演算子が成功するには、式の片方がtrueでよいので)。下の式はfalseです(左右両方の式がともにfalseなので)
console.log((6 > 5) || (10 < 9))
console.log((4 > 5) || (10 < 9))
次のスケッチは、&& 演算子を使って、マウス位置が特定の範囲内にあるかどうかを調べる例です。前に見たサンプルと似ていますが、ここでは、マウス位置が画面の上1/3より大きく、同時に下1/3より小さい場合に、円をセンターに表示します(マウスカーソルが画面真ん中辺りにある場合にだけ、円を1個センターに描画する)。そうでない場合には画面の上と下に2個円を表示します。
次のスケッチは、マウスが押されているかまたはマウス位置が画面の下半分にある場合に、円を描画する例です。
演習
矩形を描画するスケッチを記述します。マウス位置がその矩形内にある場合には、矩形を青い塗りで描画します。マウス位置が矩形の外にある場合には、矩形を赤い塗りで描画します。
範囲内にとどめる
ifステートメントと関係式の用途の1つに、範囲内に維持する、ということがあります。経時的に変化する値がある場合、それがあるしきい値を超えたかどうかを調べたい場合があります。超えた場合には、その値に何らかの操作をして値をリセットしたり、向きを変えたりします。
この分かりやすい例がボールの跳ね返りサンプルです。左から右に移動する円を描画します。円のボールは、スケッチの右端に到達したら右から左に移動し、左端に到達したら、また左から右に移動します。
跳ね返りは、xspeed変数に-1を掛けることで一般化できます。つまり、X位置が”範囲外”になったときにはつねに、その向きを反転する、ということです。
演習
上記サンプルを、ボールのXとY方向両方のスピードを追跡するように修正します。ifステートメントを追加し、Y軸方向についてボールを範囲内にとどめておくようにします(X軸方向について行っている既存のifステートメントを補完します)。