チュートリアル ループによる繰り返し

ループによる繰り返し

By Joanne Amarisa, Layla Quiñones, Greg Benedis-Grab

はじめに

わずか数行のコードで多くの図形を描くことで、プロジェクトを次のレベルに引き上げたいと思ったことはありませんか?木の列、本の山、虹のアーチ、ハチの巣の内部を描くことを想像してみてください。同じ形の変形で作られたビジュアルを作成するには、個々の形を超えてコーディングし、ループと配列の素晴らしい世界に踏み込む必要があります。わずか数行のコードで繰り返しパターンを作成する方法を学びましょう!

アーチと六角形の形が「単一オブジェクト」というラベルの付いた垂直に並んでいます。これらの形から対応するパターンへ矢印が指しており、それらは「複数オブジェクト」というラベルの下に垂直に並んでいます。単一のアーチは5つの垂直に積み重なったアーチを指し、虹の形を作っています。六角形は多くの六角形がハチの巣のテッセレーションに配置されているのを指しています。

アーチと六角形の形が「単一オブジェクト」というラベルの付いた垂直に並んでいます。これらの形から対応するパターンへ矢印が指しており、それらは「複数オブジェクト」というラベルの下に垂直に並んでいます。単一のアーチは5つの垂直に積み重なったアーチを指し、虹の形を作っています。六角形は多くの六角形がハチの巣のテッセレーションに配置されているのを指しています。

新しい行のコードで各図形を描くのは面倒なプロセスになるでしょう。代わりに、ループを使用することができます。ループを使えば、コードのブロックを好きな回数だけ実行して繰り返すことができます。このチュートリアルでは、ループと配列を使用してレースをするイモムシのスケッチを作成します。

3匹のピンクのイモムシがキャンバスの右側にある緑のゴールラインに向かってクロールしています。

3匹のピンクのイモムシがキャンバスの右側にある緑のゴールラインに向かってクロールしています。

イモムシのグループがレースのスタートラインから始まり、最初にゴールラインを通過したイモムシが勝者となります。スケッチを実行するたびに勝つイモムシは変わります!

このチュートリアルでは、以下のことを学びます:

  • forループを使用して反復的なタスクと図形を描画し、更新する
  • カスタム関数を使用して変数とプログラムの状態を更新し、スケッチの実行中にプログラムに変更を加える
  • 条件文random()を使用して異なる結果を生成する
  • マウストリガーとブール変数を使用してスケッチを実行および停止する
  • イモムシの位置を配列に格納する

必要なもの

ステップ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座標、直径を指定するためにcircXcircY、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つの文で定義されます。それらは:

for (
 let i = 0; 
 
i < number;
 
  i += 1  
) { }
初期化条件命令
  • 初期化:反復変数iを数値で初期化し、カウントを開始します。

    let i = 0;
  • 条件:ループを継続させる条件です。この条件が真である限り、forループは実行を続けます。この条件がfalseになると、forループは停止します。

    i < number;
  • 命令:ループが実行されるたびにカウント数をどのように変更するかをプログラムに指示します。

    i += 1;

最初の式let i = 0は、forループを初期化または開始します。

  • iはforループの初期状態を定義する変数です。これはインデックス変数としても知られています。通常、インデックスは0の値から始まり、ループごとに増加します。この変数の名前は好きなものを使用できます。一般的にijkなどの単一文字の変数が使用されますが、より説明的な名前を自由に使用してください。

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 += 1i++とも書くことができます。

要約すると:

  1. プログラムがforループを実行するとき、まず最初の式でループのインデックス変数を宣言します。
  2. 2番目の式(ブール式)をチェックします。それがtrueであれば、中括弧内に書かれたコードを実行します。
  3. ループの終わりに、反復変数iの値が3番目の式で定義されたように変更されます。
  4. 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分減算することで、両目が重ならずに並んで配置されます。
  • イモムシが完成したら、コードをdrawCaterpillar()という名前のカスタム関数に整理します。好みに応じてイモムシを修正してください!
    • draw()の外側でdrawCaterpillar()関数を定義します。
    • この関数には、イモムシの体のための円のforループと、イモムシの目のための2つの円を含める必要があります。
    • draw()関数内で呼び出すことを忘れないでください!ループを終了するif文の前にdraw()内でdrawCaterpillar();と入力します。

ここまでのスケッチは以下のようになるはずです:

試してみよう!

bodySizeeyeSize変数を調整して、イモムシの体と目のサイズを変えてみてください。

ステップ4 – drawCaterpillar()関数を一般化する

スケッチが最初に実行されるとき、各イモムシがスタートラインにいるようにしたいです。これは、イモムシがどこに描かれるかを指定できるように、関数にパラメータを追加する必要があることを意味します。

  • drawCaterpillar()関数に移動します。
    • 関数の括弧内にxをパラメータとして追加します:function drawCaterpillar(x) { ...}
      • drawCaterpillar()関数内でxをローカル変数として既に宣言していたことに注意してください。その宣言を削除し、代わりにxパラメータを使用できます。
    • 関数の括弧内にyを2番目のパラメータとして追加します function drawCaterpillar(x,y) { ... }
      • 関数本体内のcircYyに置き換えます。

カスタム関数、引数、パラメータについての詳細は、前回のチュートリアル関数でコードを整理すると、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を加えることで、イモムシをその行の中央に配置します。
  • ステップ5と同様に、drawCaterpillar()関数呼び出しの括弧内にyを引数として追加します。
    • コード行は次のようになるはずです:drawCaterpillar(circX, y);

要約すると、drawCaterpillar()関数内で使用するためにxとyをパラメータとして割り当てました。drawCaterpillars()でこの関数を呼び出す際に、circXyを引数として使用します。

カスタム関数、引数、パラメータについての詳細は、前回のチュートリアル関数でコードを整理するで学ぶことができます。

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で、y0.5 * paddingです。最初のイモムシはそのy値で描かれます。
  • 2回目の反復では、iは1で、y1.5 * paddingになります。2番目のイモムシは新しいy値で描かれます。
  • 3回目の反復では、iは2で、y2.5 * paddingになります。3番目のイモムシは新しいy値で描かれます。

イモムシ(ループの反復)

x

y

1番目

0

0.5 * padding

2番目

1

1.5 * padding

3番目

2

2.5 * padding

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();
}

このコードは、すべてのイモムシがゴールラインを通過したかどうかをチェックします。いずれかのイモムシがまだゴールラインに到達していない場合、allFinishedfalseに設定され、ループは続行されます。すべてのイモムシがゴールラインを通過すると、allFinishedtrueのままとなり、アニメーションは停止します。

これらの変更を加えた後、スケッチは以下のようになるはずです:

これで、各イモムシが異なる速度で移動し、すべてのイモムシがゴールラインに到達したときにアニメーションが停止するようになりました!

ステップ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);を追加してテキストを中央揃えにし、テキストにスタイルを追加します。
  • 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リファレンスや前のチュートリアルを参照して、条件文、インタラクティビティ変数関数についてさらに学んでください。

次のステップ

参考文献