By Joanne Amarisa, Layla Quiñones, Greg Benedis-Grab
はじめに
わずか数行のコードで多くの図形を描くことで、プロジェクトを次のレベルに引き上げたいと思ったことはありませんか?木の列、本の山、虹のアーチ、ハチの巣の内部を描くことを想像してみてください。同じ形の変形で作られたビジュアルを作成するには、個々の形を超えてコーディングし、ループと配列の素晴らしい世界に踏み込む必要があります。わずか数行のコードで繰り返しパターンを作成する方法を学びましょう!
新しい行のコードで各図形を描くのは面倒なプロセスになるでしょう。代わりに、ループを使用することができます。ループを使えば、コードのブロックを好きな回数だけ実行して繰り返すことができます。このチュートリアルでは、ループと配列を使用してレースをするイモムシのスケッチを作成します。
イモムシのグループがレースのスタートラインから始まり、最初にゴールラインを通過したイモムシが勝者となります。スケッチを実行するたびに勝つイモムシは変わります!
このチュートリアルでは、以下のことを学びます:
- forループを使用して反復的なタスクと図形を描画し、更新する
- カスタム関数を使用して変数とプログラムの状態を更新し、スケッチの実行中にプログラムに変更を加える
- 条件文と
random()
を使用して異なる結果を生成する - マウストリガーとブール変数を使用してスケッチを実行および停止する
- イモムシの位置を配列に格納する
必要なもの
- p5.js Web Editor
- p5.jsで基本的な図形とテキストをx座標とy座標を使って描画する理解
- 前回のチュートリアルはじめようを参照できます
- 変数と条件文の理解
- 前回のチュートリアル変数と変化と条件分岐とインタラクティビティを参照できます
- カスタム関数とパラメータの理解
- 前回のチュートリアル関数でコードを整理するを参照できます
ステップ1 – レーストラックを描く
- p5.js Web Editorで新しいプロジェクトを開き、「Caterpillar Race」のような名前を付けて保存します。
setup()
内で、500x500ピクセルのキャンバスを作成します。- スタートラインとゴールラインのx座標をそれぞれ定義するために、
setup()
の上に2つの新しいグローバル変数を宣言します。2つの変数をstartLineとfinishLineと名付けます。- スタートラインとゴールラインを配置したい場所に応じて、x軸上の値を割り当てます。この例では、startLineを30に、finishLineを360に設定します。
draw()
関数内で:- 背景色を設定します。例えば、
background(121, 96, 76);
で茶色に設定します。 - 長方形を描き、そのx座標を
startLine
に設定します。高さをheight
に設定して、キャンバスを垂直に横切るようにします。 finishLine
に別の長方形を描き、同じステップを繰り返します。- 2つの長方形を異なる色で塗りつぶします。
- 背景色を設定します。例えば、
- スケッチに名前を付けて保存することを忘れないでください。
コードは以下のようになるでしょう:
ステップ2 – イモムシの1セグメントを描いて動かす
次に、キャンバス上にイモムシの1セグメントを描き、スタートラインからゴールラインまで移動させます。レースの終わりで停止します。
circX
という新しいグローバル変数を宣言し、startLine
の値を割り当てます。- これがイモムシのセグメントのx座標になります。
circY
という新しいグローバル変数を宣言し、250(または高さの半分)の値を割り当てます。- これがイモムシのセグメントのy座標になります。
draw()
内で:circle()
関数を使用してイモムシのセグメントを描きます。x座標、y座標、直径を指定するためにcircX
、circY
、50を引数として含めます:circle(circX, circY, 50);
- 円に白の塗りつぶし色と薄い黒の輪郭線も与えます。
- 円のコマンドの下で、
circX += 20;
を使用してcircX
を20ずつ増加させます。- これは、
draw()
関数が実行されるたびに、circX
変数が20ピクセルずつ増加することを意味します。スケッチは前の円のx座標から20ピクセル右に新しい円を描き、イモムシの形を作ります。
- これは、
draw()
の最後に次の条件文を追加します:if (circX > finishLine) { noLoop(); }
noLoop()
関数はdraw()
関数が再び実行されるのを停止します。このif
文は、円のx座標がfinishLineの値を超えたときにnoLoop()
を使用してdraw()
を停止します。noLoop()
についての詳細はp5.jsリファレンスをご覧ください。
setup()
に以下を追加します:frameRate(3);
- フレームレートは
draw()
が1秒間に実行される回数です。低い数値に設定すると、このアニメーションの動きがより顕著で劇的になります。
コードは以下のようになるはずです:
If文
上記で適用されたif文のような条件文は、特定の条件が真の場合にのみ実行されるコードのブロックを指します。通常、次のように書かれます:
if (<条件>) {
<コード>
}
条件はif文の括弧内で指定されます。中括弧{ }
はコードブロックの開始と終了を示します。ステップ2では、条件circX > finishLine
は、円のx座標がfinishLine
の値より大きくなったときにnoLoop()
を呼び出すことでdraw()
の再実行を停止します。
ifについての詳細はp5.jsリファレンスをご覧ください。
ステップ3 – 1匹のイモムシを描く
ステップ2のイモムシのセグメントを繰り返して、イモムシの体を構成する円の列を作ります。forループを使用して、複数の円を一列に描きます。
3.1 – イモムシの体の特性を宣言する
setup()
の上で:
segments
という新しい変数を宣言し、6という値を割り当てます。- この変数は、イモムシの体を構成する円の数を定義します。
spacing
という新しい変数を宣言し、20という値を割り当てます。- この変数は、イモムシの体のセグメント間のピクセル間隔を定義します。
segmentSize
という新しい変数を宣言し、50という値を割り当てます。- この変数は、体のセグメントの円の直径を定義します。
3.2 – forループでイモムシの体を構築する
draw()
内で:
- ゴールラインを描くコードの後に、すべての体のセグメントを配置するための新しいローカル変数
x
を宣言します:let x = circX;
- forループを追加します:
for (let i = 0; i < length; i += 1) { }
- forループは、中括弧内に書いたコードを複数回繰り返します。
circle()
を描く行をforループの中括弧内に移動します。- forループの後に、
circX += spacing
を追加します。- これにより、
draw()
が実行されるたびにイモムシの体が右に移動します。
- これにより、
コードは以下のようになるはずです:
Forループ
forループはコードのセクション(またはブロック)を複数回実行することができます。forループは以下のように書くことができます:
for (let i = 0; i < number; i += 1) {
// number回実行したいコード
}
forループの中括弧{}
の中に、繰り返し実行したいコードを書きます。ループの条件を設定することで、コードを繰り返したい回数を指定できます。
forループは、括弧内にセミコロンで区切られた3つの文で定義されます。それらは:
|
|
|
|
|
|
|
初期化 | 条件 | 命令 |
初期化:反復変数
i
を数値で初期化し、カウントを開始します。let i = 0;
条件:ループを継続させる条件です。この条件が真である限り、forループは実行を続けます。この条件が
false
になると、forループは停止します。i < number;
命令:ループが実行されるたびにカウント数をどのように変更するかをプログラムに指示します。
i += 1;
最初の式let i = 0
は、forループを初期化または開始します。
- iはforループの初期状態を定義する変数です。これはインデックス変数としても知られています。通常、インデックスは0の値から始まり、ループごとに増加します。この変数の名前は好きなものを使用できます。一般的に
i
、j
、k
などの単一文字の変数が使用されますが、より説明的な名前を自由に使用してください。
2番目の式i < number
は、ループを継続させる条件です。これはブール式として知られており、この式はtrue
またはfalse
を返すことができます。この式がtrue
である限り、forループは実行を続け、この場合はインデックス変数(i
)が増加し続けます。
number
は任意の数値または数値を格納する変数です。カウントには整数がよく使用されます。- 例:
i < 5;
またはi < segments;
- 例:
- この場合、
number
はforループが実行される回数を決定します。これは初期値i
が0から始まるためです。 - イモムシの例では、この値を
segments
変数に設定しています。これはイモムシの体を構成する円の数を指定します。描かれた円の数がsegments
に格納された数より少ない限り、ループは円を描き続けます。- 描かれた円の数が
segments
より少なくなくなると、プログラムはforループを抜け、次のコード行に進みます。
- 描かれた円の数が
3番目の式i += 1
は、各ループ反復の終わりにインデックスがどのように変化するかを示します。
- ループ反復とは、ループが1回実行されることを指します。例えば、forループが3回実行される場合、それは3回の反復を持ちます。
- この例では、forループが実行されるたびに
i
変数が1ずつ増加します。つまり、このforループが最初に実行されるとき、i
は0です。2回目に実行されるとき、i
は1です。3回目に実行されるとき、i
は2です。そして以降も同様です(number
の値に達するまで)。この式i += 1
はi++
とも書くことができます。
要約すると:
- プログラムがforループを実行するとき、まず最初の式でループのインデックス変数を宣言します。
- 2番目の式(ブール式)をチェックします。それが
true
であれば、中括弧内に書かれたコードを実行します。 - ループの終わりに、反復変数
i
の値が3番目の式で定義されたように変更されます。 - 2番目の式の条件が
false
になるまで、このプロセスを繰り返します。条件がfalse
になると、プログラムはforループを抜け、スケッチの次のコード行に進みます。
詳細についてはforループのリファレンスをご覧ください。
3.3 – イモムシにさらに詳細を追加する
- イモムシの体の
fill()
色を必要に応じて調整します。この例では、ピンク色を与えます:fill(255, 0, 200);
- イモムシの目を描きます。目の位置は、体のために描かれた最後の円のx座標とy座標と同じです。これは、forループがすべての円を描いた後になるので、forループの後、但し
noLoop()
の前に目を追加します。これにより、目がイモムシの体の最後の円の上に描かれることが保証されます。setup()
の上に新しいグローバル変数eyeSize
を宣言し、15の値を割り当てます。- 2つの円を描きます。
- 黒の塗りつぶしと太い白の輪郭線を与えます。
- 最初の目を追加し、その座標とサイズを設定します:
circle(x, circY-eyeSize, eyeSize);
- これにより、目が最後に描かれた円の上部に配置されます。
- 2つ目の目を追加し、その座標とサイズを設定します:
circle(x - eyeSize, circY-eyeSize, eyeSize);
- 2つ目の目のx座標を
eyeSize
分減算することで、両目が重ならずに並んで配置されます。
- 2つ目の目のx座標を
- イモムシが完成したら、コードを
drawCaterpillar()
という名前のカスタム関数に整理します。好みに応じてイモムシを修正してください!draw()
の外側でdrawCaterpillar()
関数を定義します。- この関数には、イモムシの体のための円のforループと、イモムシの目のための2つの円を含める必要があります。
draw()
関数内で呼び出すことを忘れないでください!ループを終了するif文の前にdraw()
内でdrawCaterpillar();
と入力します。
ここまでのスケッチは以下のようになるはずです:
試してみよう!
bodySize
とeyeSize
変数を調整して、イモムシの体と目のサイズを変えてみてください。
ステップ4 – drawCaterpillar()
関数を一般化する
スケッチが最初に実行されるとき、各イモムシがスタートラインにいるようにしたいです。これは、イモムシがどこに描かれるかを指定できるように、関数にパラメータを追加する必要があることを意味します。
drawCaterpillar()
関数に移動します。- 関数の括弧内に
x
をパラメータとして追加します:function drawCaterpillar(x) { ...}
drawCaterpillar()
関数内でx
をローカル変数として既に宣言していたことに注意してください。その宣言を削除し、代わりにx
パラメータを使用できます。
- 関数の括弧内に
y
を2番目のパラメータとして追加しますfunction drawCaterpillar(x,y) { ... }
- 関数本体内の
circY
をy
に置き換えます。
- 関数本体内の
- 関数の括弧内に
カスタム関数、引数、パラメータについての詳細は、前回のチュートリアル関数でコードを整理すると、p5.jsの関数のリファレンスで学ぶことができます。
カスタム関数は以下のようになるはずです:
function drawCaterpillar(x,y) {
// 体を形成するために
// 円のループを作成します。
for (let i = 0; i < segments; i += 1) {
fill(255, 0, 200);
stroke(0);
strokeWeight(1);
circle(x, y, 50);
x += spacing;
}
// イモムシの目を描きます。
fill(0);
stroke(255);
strokeWeight(3);
circle(x, y - eyeSize, eyeSize);
circle(x - eyeSize, y - eyeSize, eyeSize);
}
draw()
内で、drawCaterpillar()
を3回呼び出して3匹のイモムシを得ます
draw関数は以下のようになるはずです:
function draw() {
// 背景を描きます。
background(121, 96, 76);
// スタートラインとゴールラインを描きます。
noStroke();
fill(0);
rect(startLine, 0, 5, height);
fill(0, 255, 0);
rect(finishLine, 0, 20, height);
// 3匹のイモムシを描きます。
drawCaterpillar(circX,circY-150);
drawCaterpillar(circX,circY);
drawCaterpillar(circX,circY+150);
circX += spacing;
// xがゴールラインに
// 到達したらループを終了します。
if (circX > finishLine) {
noLoop();
}
}
ステップ5 – drawCaterpillars()
関数を作成する
これで、3匹のイモムシが同時に画面を横切って移動しています。drawCaterpillar()
への3つの個別の関数呼び出しの代わりに、ループを使用して3匹のイモムシを描くことができます。
- スケッチの
setup()
の上に、レースに参加させたいイモムシの数のための新しいグローバル変数を宣言します:let numCaterpillars = 3;
draw()
の外側に新しいカスタム関数を作成し、drawCaterpillars()
と名付けますdrawCaterpillars()
関数内に新しいforループを作成します。- ループの最初の式でループの変数を0で初期化して開始します。
- ループの2番目の式で条件を
i < numCaterpillars
に設定します。 - 3番目の式でループの変数をインクリメントします。
- forループの中括弧内で
drawCaterpillar(circX, circY);
を呼び出します。
draw()
内で、drawCaterpillars();
を呼び出します。
draw()
とdrawCaterpillars()
関数は以下のようになるはずです:
let numCaterpillars = 3;
// ...変数宣言とsetup
function draw() {
// 背景を描きます。
background(121, 96, 76);
// スタートラインとゴールラインを描きます。
noStroke();
fill(0);
rect(startLine, 0, 5, height);
fill(0, 255, 0);
rect(finishLine, 0, 20, height);
circX += spacing;
// キャンバス上にイモムシを描きます
drawCaterpillars();
// xがゴールラインに
// 到達したらループを終了します。
if (circX > finishLine) {
noLoop();
}
}
function drawCaterpillars() {
for (let i = 0; i < numCaterpillars; i += 1) {
drawCaterpillar(circX,circY);
}
}
スケッチは実行されるはずですが、今回は1匹のイモムシしか見えないでしょう。これは、3匹のイモムシがすべて重なって描かれているためです。次のステップでは、各イモムシのy座標を調整してこれを修正します:
ステップ6 – レースのためにイモムシを配置する
復習! ステップ3と4から、スケッチに2つのカスタム関数があります。
drawCaterpillar(x,y)
は、xとyのパラメータを使用して1匹のイモムシを描きます。drawCaterpillars()
はdrawCaterpillar()
関数を呼び出し、それをforループ内に配置して複数のイモムシを描くことができるようにします。
現在、各イモムシは同じx座標とy座標にあります。forループ内のコードを調整して、y座標でイモムシを間隔を空けて配置します。
drawCaterpillars()
関数の宣言に移動します。- forループ内に、新しいコード行を追加します:
let padding = height / numCaterpillars;
- これは
padding
という新しい変数を宣言し、各イモムシ間の垂直方向の間隔を決定します。 - キャンバスの
height
をスケッチ内のイモムシの数で割った値を割り当てます。これにより、キャンバスが垂直方向に行(各イモムシに1つずつ)に分割されます。各行の高さがpadding
の値になります。
- これは
y
変数を初期化し、この値を割り当てます:let y = (i + 0.5) * padding
、ここでy
は各イモムシのy座標を決定します。i
変数を使用することで、forループの各反復で1匹のイモムシを自身の行に配置します。i
に0.5を加えることで、イモムシをその行の中央に配置します。
- forループ内に、新しいコード行を追加します:
- ステップ5と同様に、
drawCaterpillar()
関数呼び出しの括弧内にy
を引数として追加します。- コード行は次のようになるはずです:
drawCaterpillar(circX, y);
- コード行は次のようになるはずです:
要約すると、drawCaterpillar()
関数内で使用するためにxとyをパラメータとして割り当てました。drawCaterpillars()
でこの関数を呼び出す際に、circX
とy
を引数として使用します。
カスタム関数、引数、パラメータについての詳細は、前回のチュートリアル関数でコードを整理するで学ぶことができます。
drawCaterpillars()
関数は今のところ以下のようになるはずです:
function drawCaterpillars() {
for (let i = 0; i < numCaterpillars; i += 1) {
let padding = height/numCaterpillars;
let y = (i + 0.5) * padding;
drawCaterpillar(circX, y, 6);
}
}
forループのインデックス変数を使用した描画
forループのインデックス変数(i
)は、ループの各反復で段階的に増加または減少させることができます。このチュートリアルでは、i
変数は0から始まり、forループが実行されるたびに1ずつ増加します。
- このforループが最初に実行されるとき、
i
は0です。 - ループが2回目に実行されるとき、
i
は1です。 - 3回目に実行されるとき、
i
は2です。以降も同様です。
forループの各反復で結果が異なるように、インデックス変数を使用して描画時に数値を加算、減算、乗算、除算することができます。
この例では、i
を使用して各イモムシ間の一貫した間隔を計算しています(以下の表を参照):
- 最初の反復では
i
は0で、y
は0.5 * padding
です。最初のイモムシはそのy値で描かれます。 - 2回目の反復では、
i
は1で、y
は1.5 * padding
になります。2番目のイモムシは新しいy値で描かれます。 - 3回目の反復では、
i
は2で、y
は2.5 * padding
になります。3番目のイモムシは新しいy値で描かれます。
イモムシ(ループの反復) |
|
|
---|---|---|
1番目 | 0 |
|
2番目 | 1 |
|
3番目 | 2 |
|
drawCaterpillar()
とdrawCaterpillars()
は以下のようになるはずです:
// ... 変数宣言、setup()、draw()
function drawCaterpillars() {
for (let i = 0; i < numCaterpillars; i += 1) {
// 各イモムシ間の間隔。
let padding = height / numCaterpillars;
let y = (i + 0.5) * padding;
// イモムシを描く
drawCaterpillar(circX, y);
}
}
function drawCaterpillar(x, y) {
// 体を形成するために
// 円のループを作成します。
for (let i = 0; i < segments; i += 1) {
fill(255, 0, 200);
stroke(0);
strokeWeight(1);
circle(x, y, 50);
x+=spacing;
}
// イモムシの目を描きます。
fill(0);
stroke(255);
strokeWeight(3);
circle(x, y - eyeSize, eyeSize);
circle(x - eyeSize, y - eyeSize, eyeSize);
}
全体は以下のようになるはずです:
試してみよう!
numCaterpillars
グローバル変数の値を変更して、drawCaterpillars()
のforループがキャンバス上で垂直方向にどのようにイモムシを間隔を空けて配置するかを確認してください。
ステップ7 – イモムシの位置を配列に格納する
現在、すべてのイモムシは同じ速度で移動しています。各イモムシに異なる速度を与えるために、イモムシの位置を個別に追跡する必要があります。これを行うために、配列を使用します。
配列は、複数の値を1つの変数に格納するのに役立ちます。配列内の各値は要素と呼ばれ、各要素にはインデックスがあります。インデックスは配列内の要素の位置を示し、0から始まります。
例えば、3つの数値を持つ配列は以下のようになります:
let myArray = [10, 20, 30];
この配列では:
- インデックス0の要素は10です
- インデックス1の要素は20です
- インデックス2の要素は30です
配列の要素にアクセスするには、配列名の後に角括弧[]を使用し、その中にインデックスを入れます。例えば:
console.log(myArray[0]); // 10を出力
console.log(myArray[1]); // 20を出力
console.log(myArray[2]); // 30を出力
7.1 – イモムシの位置を格納する配列を作成する
setup()
の上に、新しいグローバル変数caterpillarX
を宣言します:let caterpillarX = [];
- 空の角括弧
[]
は、この変数が空の配列であることを示します。
- 空の角括弧
setup()
内で、forループを使用してcaterpillarX
配列にイモムシの開始位置を追加します:
function setup() {
createCanvas(500, 500);
frameRate(3);
for (let i = 0; i < numCaterpillars; i += 1) {
caterpillarX.push(startLine);
}
}
push()
メソッドは配列の末尾に新しい要素を追加します。この場合、各イモムシの開始位置(startLine
の値)を配列に追加しています。
7.2 – 配列を使用してイモムシを描画する
drawCaterpillars()
関数を更新して、caterpillarX
配列の値を使用します:
function drawCaterpillars() {
for (let i = 0; i < numCaterpillars; i += 1) {
let padding = height / numCaterpillars;
let y = (i + 0.5) * padding;
drawCaterpillar(caterpillarX[i], y);
}
}
ここでは、circX
の代わりにcaterpillarX[i]
を使用しています。これにより、各イモムシは配列内の対応する位置の値を使用します。
7.3 – イモムシを個別に移動させる
draw()
関数内のcircX += spacing;
の行を削除します。- 代わりに、forループを使用して各イモムシを個別に移動させます:
function draw() {
// 背景を描きます。
background(121, 96, 76);
// スタートラインとゴールラインを描きます。
noStroke();
fill(0);
rect(startLine, 0, 5, height);
fill(0, 255, 0);
rect(finishLine, 0, 20, height);
// 各イモムシを移動させます
for (let i = 0; i < numCaterpillars; i += 1) {
caterpillarX[i] += spacing;
}
// キャンバス上にイモムシを描きます
drawCaterpillars();
// いずれかのイモムシがゴールラインに
// 到達したらループを終了します。
if (caterpillarX[0] > finishLine) {
noLoop();
}
}
これで、各イモムシの位置が個別に更新されます。ただし、現時点ではすべてのイモムシが同じ速度で移動しています。
ステップ8 – イモムシにランダムな速度を与える
各イモムシに異なる速度を与えるために、random()
関数を使用してランダムな値を生成します。
8.1 – 速度の配列を作成する
setup()
の上に、新しいグローバル変数caterpillarSpeed
を宣言します:let caterpillarSpeed = [];
setup()
内で、forループを使用してcaterpillarSpeed
配列にランダムな速度を追加します:
function setup() {
createCanvas(500, 500);
frameRate(3);
for (let i = 0; i < numCaterpillars; i += 1) {
caterpillarX.push(startLine);
caterpillarSpeed.push(random(1, 5));
}
}
random(1, 5)
は1から5の間のランダムな数値を生成します。これにより、各イモムシは異なる速度を持つことになります。
8.2 – ランダムな速度を使用してイモムシを移動させる
draw()
関数内のイモムシを移動させるforループを更新します:
// 各イモムシを移動させます
for (let i = 0; i < numCaterpillars; i += 1) {
caterpillarX[i] += caterpillarSpeed[i];
}
これで、各イモムシは自身の速度で移動します。
8.3 – すべてのイモムシがゴールラインに到達したらアニメーションを停止する
現在、最初のイモムシ(インデックス0)がゴールラインに到達したときにアニメーションが停止します。代わりに、すべてのイモムシがゴールラインを通過したときにアニメーションを停止するようにしましょう。
draw()
関数内のif文を更新します:
// すべてのイモムシがゴールラインに到達したかチェックします
let allFinished = true;
for (let i = 0; i < numCaterpillars; i += 1) {
if (caterpillarX[i] <= finishLine) {
allFinished = false;
break;
}
}
if (allFinished) {
noLoop();
}
このコードは、すべてのイモムシがゴールラインを通過したかどうかをチェックします。いずれかのイモムシがまだゴールラインに到達していない場合、allFinished
はfalse
に設定され、ループは続行されます。すべてのイモムシがゴールラインを通過すると、allFinished
はtrue
のままとなり、アニメーションは停止します。
これらの変更を加えた後、スケッチは以下のようになるはずです:
これで、各イモムシが異なる速度で移動し、すべてのイモムシがゴールラインに到達したときにアニメーションが停止するようになりました!
ステップ9 – マウストリガーでレースを開始する
isRacing
という新しいブール型のグローバル変数を宣言し、false
に設定します:let isRacing = false
;- この変数は状態変数として機能し、イモムシがレース中かどうかの情報をブール値(
true
またはfalse
)として保存します。
- この変数は状態変数として機能し、イモムシがレース中かどうかの情報をブール値(
mousePressed()
関数を定義します。- 関数内で、
isRacing
ブール値をtrue
に設定します。
- 関数内で、
関数は次のようになります:
// ユーザーがマウスを押したときに // レースを開始します。 function mousePressed() { isRacing = true; }
draw()
関数内で、drawCaterpillars()
関数呼び出しの前に新しいif文を作成します:if (isRacing === true) { }
moveCaterpillars()
関数呼び出しをif文の中に移動します。- これにより、イモムシはレースが始まった後(マウスが押された後)にのみ動き始めます。
コードは次のようになります:
// ... グローバル変数を定義
let isRacing = false;
function setup() {
createCanvas(500, 500);
// フレームレートを遅く設定します。
frameRate(3);
for (let i=0;i<numCaterpillars;i++) {
caterpillarEnds.push(startLine)
}
}
function draw() {
// 背景を描画します。
background(121, 96, 76);
// スタートラインとゴールラインを描画します。
noStroke();
fill(0);
rect(startLine, 0, 5, height);
fill(0, 255, 0);
rect(finishLine, 0, 20, height);
// レースが開始されていれば
// イモムシを動かします。
if (isRacing === true) {
moveCaterpillars();
}
drawCaterpillars();
}
// ユーザーがマウスを押したときに
// レースを開始します。
function mousePressed() {
isRacing = true;
}
// ... moveCaterpillars、drawCaterpillars、drawCaterpillar関数。
ステップ10 – レースの開始と終了のメッセージを追加する
よくできました!この段階のスケッチでは、マウスをクリックすると開始するイモムシのレースができています。
あとは、プログラムの使い方をキャンバス上に指示を追加するだけです。また、レースの終了時に勝利したイモムシを発表するメッセージも追加します。勝者はランダムになります。noLoop()関数を再び追加して、勝者が宣言されたらレースが終了するようにします。
10.1 – スタートメッセージを書く
draw()
の後に新しいカスタム関数を作成し、writeStart()
と名付けます。関数内に以下を追加します:
text(" 🏁 Click to start!", width / 2, height / 2);
- これは指示テキストを書き、キャンバスの中央に配置します。
textAlign(CENTER);
をtext()
コマンドの上に追加して、テキストを中央揃えにします。- テキストにスタイルを追加します。この例では、白色で輪郭線なし、テキストサイズ24にします。
writeStart()
関数は次のようになります:function writeStart() { // テキストのスタイルを設定します。 textSize(24); textAlign(CENTER); fill(255); noStroke(); // メッセージを表示します。 text("🏁 Click to start!", width / 2, height / 2); }
draw()
関数に戻り、else文を追加します:else {}
- このelse文は、レースがまだ開始されていない場合に実行されます
このelse文のコードブロック内で
writeStart()
関数を呼び出します。
draw()
関数は次のようになります:
function draw() {
// 背景を描画します。
background(121, 96, 76);
// スタートラインとゴールラインを描画します。
noStroke();
fill(0);
rect(startLine, 0, 5, height);
fill(0, 255, 0);
rect(finishLine, 0, 20, height);
// レースが開始されていれば
// イモムシを動かします。
if (isRacing === true) {
moveCaterpillars();
} else {
// レースが開始されていない場合、
// 開始方法の指示を書きます。
writeStart();
}
// 新しい位置にイモムシを描画します
drawCaterpillars();
}
10.2 – 勝者をチェックし、誰が勝ったかを表示する
イモムシの一匹が勝ったかどうかをチェックする必要があります。勝者がいれば、その情報を表示してレースを終了させます。
draw()
の下に新しい関数を作成して勝者をチェックします:function checkWinner() {}
関数の中括弧内に、各イモムシのx値をチェックして勝者がいるかどうかを確認するforループを書きます:
for (let i = 0; i < caterpillarEnds.length; i += 1) {}
forループの中括弧内に、各イモムシがゴールラインを越えたかどうかを確認するif文を含めます:
if (caterpillarEnds[i] >= finishLine) {}
このif文の中で、テキストリテラルを使用して勝者を動的にテキストに書き込みます:
text(`Caterpillar ${i + 1} wins!`, width / 2, height / 2);
- これは勝ったイモムシのインデックスを動的に表示するテキストを書きます。インデックスは0から始まり、通常イモムシは1から数えるので、
i
の値に1を加えています。 - ステップ9.1と同様に、
textAlign(CENTER);
を追加してテキストを中央揃えにし、テキストにスタイルを追加します。
- これは勝ったイモムシのインデックスを動的に表示するテキストを書きます。インデックスは0から始まり、通常イモムシは1から数えるので、
if文の中に
noLoop()
関数も含めて、draw()
の実行を停止させます。
checkWinner()
関数は次のようになります:
function checkWinner() {
for (let i = 0; i < caterpillarEnds.length; i += 1) {
if (caterpillarEnds[i] >= finishLine) {
// テキストのスタイルを設定します。
textSize(24);
textAlign(CENTER);
fill(255);
noStroke();
// メッセージを表示します。
text(`Caterpillar ${i + 1} wins!`, width / 2, height / 2);
noLoop();
}
}
}
最終的なスケッチは次のようになります:
まとめ
このチュートリアルを完了、おめでとうございます! ここでは、p5.jsでループを使用して複数の動く形を生成する方法を学びました。 p5.jsリファレンスや前のチュートリアルを参照して、条件文、インタラクティビティ、 変数、関数についてさらに学んでください。
次のステップ
- 次のチュートリアル: データ構造ガーデン