チュートリアル データ構造ガーデン

データ構造ガーデン

By Portia Morrell, Jaleesa Trapp, Kate Maschmeyer

ユーザーがマウスポインターでクリックすると、薄い青色のキャンバスに花が現れるインタラクティブな花園のプレビュー。

ユーザーがマウスポインターでクリックすると、薄い青色のキャンバスに花が現れるインタラクティブな花園のプレビュー。

このチュートリアルでは、p5.jsを使用してインタラクティブな花園をシミュレーションします。このプロジェクトでは、デジタルキャンバスに20個のランダムに生成された花が登場し、それぞれ異なる色とサイズを持ちます。ユーザーはキャンバスをクリックして新しいユニークな花を追加し、庭の多様性を増やすこともできます。各花には萎れるアニメーションがプログラムされています。このアニメーションにより、花は自然な花の寿命サイクルのように、ゆっくりと縮小して消えていきます。

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

  • JavaScriptオブジェクトを定義、作成、使用することで、データ構造を探索します。
  • JavaScript配列のようなビルトインオブジェクトに対してアクションを実行するためのオブジェクトメソッドを探索し、使用します。
  • 複数のオブジェクトを一度に管理するために、forループを使用した反復処理を行います。

前提条件

始める前に、以下のことができるようになっている必要があります:

  • p5.jsを使用してキャンバス上に図形や色を追加およびカスタマイズする
  • カスタム変数、パラメータと戻り値を持つ関数を宣言、初期化、使用、更新する
  • キャンバス上にアニメーションを追加する
  • コードにコメントを付け、エラーメッセージに対処する
  • カスタム関数を作成し使用する
  • 繰り返しタスクを管理するためにforループを使用する方法を理解する

配列、ループ、カスタム関数の詳細については、関数によるコードの整理ループによる繰り返しのチュートリアルをご覧ください。

  • 変数と変更チュートリアルでは、変数を使用してデータを保存する方法を学びました。変数は数値やテキストなどの単一の値を保存するのに便利です。
  • メディアオブジェクトによるアニメーションチュートリアルでは、p5.jsのビルトインのp5.Imagep5.Graphicsオブジェクトの使用方法を学びました。これらのオブジェクトは、画像などのデータをメソッドと呼ばれる特別な関数とバンドルし、ユーザーがそのデータに対して操作を実行できるようにします。

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

  • オブジェクトを定義する
  • オブジェクトを更新し描画するためのカスタム関数を作成し使用する
  • 配列を使用して複数のオブジェクトを管理する

それでは始めましょう!

JavaScriptオブジェクト

変数は一度に1つの値(数値、文字列、またはブール値)を保存できることを学びました。配列はインデックスに複数の値を保存できます。しかし、時には1つのものに関連する複数のデータを一緒に保存したいことがあります。これをJavaScriptオブジェクトを使用して行うことができます。オブジェクトはプロパティと値をペアにしてデータをバンドルします。プロパティはオブジェクトに関連付けられた特別な種類の変数または名前です。各プロパティは値を保存します。例えば、花に基づいてJavaScriptオブジェクトを作成したい場合、その位置(xとy)と絵文字シンボルを記述するプロパティを持つことができます。

ステップ1:最初のオブジェクトを作成する

花園を1つの花から始めましょう。絵文字を使って描くことから始めるので、花のx座標、y座標、絵文字に関するデータが必要です。

  • 新しいp5.jsプロジェクトを開き、「Data Structure Garden」と名付けます。プロジェクトを保存します。

  • 花のキャンバス座標と描画に使用する絵文字をバンドルして、花オブジェクトを作成します。このオブジェクトをflowerという名前の変数に保存しましょう。setup()の上にこのコードを追加します:

    // 花オブジェクト
    let flower = { 
      x: 200, 
      y: 100, 
      emoji: '🌸'
    };
  • setup()に以下のコード行を追加して、オブジェクトをコンソールに出力します:

    // オブジェクトをコンソールに出力
    console.log(flower);
  • 背景を"lightblue"に設定します。

コードは以下のようになるはずです:

p5.js Web Editorでここまでのコードを開いてみてください。 コンソールに花オブジェクトが出力されているはずです。コンソールの矢印をクリックすると、オブジェクトのプロパティと値が表示されることに注目してください。

オブジェクトを定義する一般的な構文は以下の通りです:

// オブジェクトを定義する
let オブジェクト名 = {
  プロパティ1: 値1,
  プロパティ2: 値2,
  プロパティ3: 値3
};

オブジェクトの構文は以下を使用します:

  • 中括弧({})でプロパティのバンドルを囲みます;

    • プロパティは変数や関数の名前のような名前、または文字列にすることができます。プロパティ名にスペースを使用する場合、文字列を使用すると便利なことがよくあります。例えば、「名」と「姓」のプロパティを持つオブジェクトを作成する場合、次のようになります:

      let ironMan = { 
        "first name" : "Tony",
        "last name" : "Stark"
      }
  • コロン(:)で各プロパティと特定の値を区切ります;

    • 値は任意のデータ型にすることができ、関数でさえ可能です!
  • カンマ(,)で各プロパティ : 値のペアを区切ります。

オブジェクト名
let 
flower
 = {
  
    x    
: 
  200  
,
プロパティ
  
    y    
: 
  200  
,
プロパティ
  
  emoji  
: 
  "🌸" 
プロパティ
}

オブジェクトを定義するときに新しい変数を初期化することで、オブジェクトを保存できます。上のコードでは、flowerという名前の変数を宣言しました。そして、キャンバス上に描画できる花を表すプロパティを持つオブジェクトでflower変数を初期化しました。

オブジェクトのプロパティと値を確認するために、console.log()を使用しました。これにより、コンソールに以下のように表示されます:

▼ {x: 200, y: 100, emoji: "🌸"}
   x: 200`
   y: 100`
   emoji: "🌸"

ステップ2:オブジェクトを使用する

オブジェクトのプロパティに保存されている任意の値には、その変数名、プロパティ名、そしてドット表記を使用してアクセスできます:

// ドット表記を使用してオブジェクトのプロパティ1の値にアクセスする
オブジェクト名.プロパティ1 
  • 花オブジェクトのプロパティを使用して、text()関数で花をキャンバス上に配置します。

    • draw()内に以下のコードを追加します:

      // 花オブジェクトを表示する
      text(flower.emoji, flower.x, flower.y);
  • text関数の前にtextSize()を使用して、花のサイズを設定できます。

    // テキスト/絵文字のサイズを大きくする
    textSize(100);

コードは以下のようになるはずです:

花オブジェクトの値にアクセスするために、ドット表記を使用しています。これはドット演算子を使用してオブジェクト内のプロパティと値にアクセスします。

上のコードでは、以下にアクセスしています:

  • flower.emojiで花の絵文字
  • flower.xでx座標
  • flower.yでy座標

これらの値は文字列と数値を表すので、変数名が保存する値にアクセスするのと同様に、text()関数で使用できます。

p5.jsリファレンスでオブジェクトについてもっと学ぶことができます。

試してみよう!
  • 花オブジェクトにsizeプロパティを追加してください。
  • textSize()の値をflowerオブジェクトのsizeに置き換えてください。

例。

ステップ3:createFlower()関数を定義する

次に、キャンバス上に異なる花を表示できる関数を定義しましょう。作成する花オブジェクトをカスタマイズできるcreateFlower()関数を定義します。異なる花のx座標とy座標を変更できるようにしたいです。また、サイズと色も変更したいです。それを行う一つの方法は、花オブジェクトにsizecolorの新しいプロパティを追加することです。このプロジェクトでは、花が現れてから一定時間後に消えるようにしたいので、花オブジェクトにlifespanプロパティも含めます。

createFlower()が呼び出されたときに情報を返すようにしたいです。ちょうどビルトインのtext()関数がキャンバス上にテキストを返すのと同じように。そのため、戻り値を指定する必要があります。戻り値を使用することは、関数によって計算された情報を変数や配列に保存する素晴らしい方法です。

この例では、random()を使用して、キャンバス上に描画されるときに花に多様性を持たせます。

  • ランダムな花オブジェクトを作成するcreateFlower()関数を定義します。createFlower()が呼び出されるたびに、すべての値がランダムに設定されます。

    • draw()setup()の外側に、以下の関数宣言を追加します:

      // ランダムな花オブジェクトを作成する関数
      function createFlower() {
        // 花オブジェクトを定義する
        let flower = {
          x: random(20, 380),
          y: random(20, 380),
          size: random(20, 75),
          lifespan: random(255, 300),
          color: color(random(255), random(255), random(255)),
        };
        // 花オブジェクトを返す
        return flower;
      }
  • createFlower()関数をテストするために、それを使用して花オブジェクトを作成し、myFlowerという変数に保存します。

    • draw()関数に以下を追加します:

      // 花オブジェクトを作成する
      let myFlower = createFlower();
  • myFlowerのプロパティを使用してキャンバス上に楕円を描画します。

    • draw()関数に以下を追加します:

      // 花オブジェクトのプロパティを使用して楕円を描画する
      fill(myFlower.color);
      ellipse(myFlower.x, myFlower.y, myFlower.size);
  • 各花が現れる速度を遅くするために、フレームレートを1秒あたり1フレームに変更します。setup()に以下を追加します:frameRate(1);

コードは以下のようになるはずです:

上のコードでは、createFlower()を使用してランダムな値を持つ新しい花オブジェクトを作成して返し、それをmyFlower変数に保存しています。myFlowerを使用してそのプロパティのランダムな値にアクセスし、それらを使用してキャンバス上に楕円を描画します。draw()が実行されるたびに、新しいランダムな花オブジェクトが作成され、そのプロパティを使用してキャンバス上に新しいランダムな楕円が描画されます。

p5.jsリファレンスでreturn値とrandom()についてもっと学ぶことができます。

試してみよう!
  • 花のxyの位置、サイズのランダムな範囲を変更してください。
  • 色の生成を創造的にしてみてください。例えば、青、赤、または紫の色合いだけにするなど。

例。

ステップ4:パラメータを持つdrawFlower()関数を定義する

createFlower()が新しい花オブジェクトを作成して返すことがわかったので、drawFlower()関数を定義しましょう。drawFlower()関数は花オブジェクトを引数として受け取り、それをキャンバス上に配置します。これにより、コードが整理され管理しやすくなります。

  • 他のすべての関数の外側で、花オブジェクトを表す1つのパラメータを持つdrawFlower()関数を定義します。

    function drawFlower(flower) { }
  • drawFlower()関数の内部で、花びらと花の中心を含む花の属性を描画します。花オブジェクトのプロパティをxyの位置、sizecolorに使用することを忘れないでください。以下のコードを関数本体に追加できます:

    noStroke();
    fill(flower.color);
    
    // 花びらを描画する
    ellipse(flower.x, flower.y, flower.size / 2, flower.size); 
    ellipse(flower.x, flower.y, flower.size, flower.size / 2);
    
    // 黄色の中心を描画する
    fill(255, 204, 0);
    circle(flower.x, flower.y, flower.size / 2);
  • 次に、drawFlower()関数をテストします。draw()関数に以下を追加します:

    // drawFlower()をテストする
    let flower1 = createFlower();
    drawFlower(flower1);

コードは以下のようになるはずです:

上のコードでは、createFlower()を使用してランダムな花を作成し、それをflower1に保存しています。そしてランダムな花(flower1)をdrawFlower()に渡し、花オブジェクトのプロパティにアクセスしてキャンバス上に花を描画します。このプロセスはdraw()関数が実行されるたびに発生するので、ランダムな花がキャンバス上に現れては消えます。

試してみよう!

他の2D形状を使用して花の描画を変更・修正してください:

例。

ステップ5:配列の使用方法を学ぶ

配列を使用して花の庭を作る前に、いくつかの簡単な例で配列の動作をよりよく理解しましょう。JavaScript配列は1つの変数名で複数の値を保存できるオブジェクトです。各値はインデックスと呼ばれる特定の位置に要素として保存されます。任意のJavaScript配列の最初の要素インデックスは0です。

例1:名前の配列の作成と描画

let flowers = [
"Rose"
, 
"Daisy"
, 
"Tulip"
];
012

この例では、角括弧([ ])とカンマを使用して配列を作成しています。配列内の各要素はカンマで区切られています。配列は花の種類を表す文字列のコレクションで、flowersという変数に保存されています。配列の各要素は花の名前を持つ文字列を保持しています。各要素にはインデックス番号を使用してアクセスできます。例えば、"Rose"はインデックス0に、"Daisy"はインデックス1に、"Tulip"はインデックス2にあります。

要素を保存する変数名指す配列配列内のインデックス
let 
   rose   
 = 
flowers
[
   0   
];

上のコードスニペットでは、インデックス表記flowers[0]を使用してflowers配列の最初の要素(インデックス0)にアクセスしています。上の例では、この構文を使用してflowers配列のさまざまな要素からアクセスした名前をキャンバス上にテキストとして配置しています。

そして、その値をroseという新しい変数に割り当てています。roseは now flowers配列の最初の花の名前である文字列"Rose"を保持します。他の要素に保存されている値も同じ方法でアクセスできます。

例2:forループを使用して名前の配列を反復処理する

2つ目の例では、forループを使用して配列の各要素を反復処理し、テキストをキャンバスに表示しています。反復は、配列の各要素に対してコードブロックが繰り返し実行されるプロセスです。

インデックス0から見始める…配列の終わりまで
for (
let i = 0;
 
i < flowers.length
; i += 1) {
  text(
flowers[i]
, 10, 50+(50 * i));
要素iの花を取得する
}

反復処理を行うために、上のコードスニペットではforループを使用して花の配列の各要素を「見ていきます」。forループによると、インデックスi0から始まり、配列の要素数よりも1小さい数に達するまで各反復で増加します。配列はインデックスを0から始めるため、配列の最後の要素のインデックスは配列の要素数よりも1小さくなります。任意の配列の要素数はarray.lengthプロパティを使用してアクセスできます。上のforループでは、flowers.lengthを使用してflowers配列の長さにアクセスしています。配列の値にアクセスするために、forループ内のtext()関数でflowers[i]を使用して、各要素の値をキャンバス上にテキストとして表示しています。

例3:配列に新しい要素を追加する

let flowers = ["Rose", "Daisy", "Tulip"
        
];
プッシュされた要素がここに追加されます
flowers
.push("Sunflower");
flowers配列の末尾に新しい要素を追加する

配列メソッドarray.push()を使用して、配列の末尾に新しい要素を追加できます。この例では、"Sunflower"flowers配列の末尾に追加しています。

例4:配列要素の削除

let flowers = [
"Rose"
, 
"Daisy"
, 
"Tulip"
];
012
flowers.splice(
   0   
, 
   1   
);
このインデックスから…1つの要素を削除する

配列から要素を削除するために、array.splice()関数を使用します。array.splice()関数は2つのパラメータを持つflowers配列を変更します:1つは開始インデックス、もう1つは削除する要素の数です。flowers.splice(0,1)の結果、配列から"Rose"が削除され、"Daisy""Tulip"だけが残ります。

例5:配列に対するfor..ofループの使用

現在の要素を保存する変数を宣言する配列をループするためのキーワードループする配列
for (
let flower
 
   of   
 
flowers
) {
  print(
   flower   
);
現在の要素で何かを行う
}

for..ofループを使用して配列を反復処理することもできます。flower変数はループの反復中に各要素を一時的に保存します。ループ内のprint(flower)文は各花の名前をコンソールに出力し、順番に"Rose""Daisy""Tulip"を表示します。

for..ofループを使用すると、物事が複雑になったときにコードが読みやすくなることがあります。以下の例を参照してください:インデックスを使用したforループ vs for..ofループ

ステップ6:配列を使用して複数の花を生成する

さて、配列を使用して画面上に複数の花を生成する時が来ました。

  • まず、プログラムの先頭でflowers配列を宣言します。空の角括弧は空の花の配列を表します。

    // 花の配列
    let flowers = [];
  • 他のすべての関数の外側で、flowerPower()関数を定義します。

    // 20個の花を作成する関数
    function flowerPower() {}
  • flowerPower()内で、forループを使用して20個の花オブジェクトを作成し、flowers配列に追加します。

    for(let i = 0; i < 20; i += 1) {
      // ランダムな位置に花を作成する
      let flower = createFlower();
      // 花を花の配列に追加する
      flowers.push(flower);
    }
  • setup()関数内でflowerPower()関数を呼び出して、20個の花オブジェクトを作成します。

    // 20個の花を生成する
    flowerPower();
  • draw()関数内で配列用のfor..ofループを使用して、flowers配列内の各花を描画します。for..ofループは、花の配列内の各花要素に対してdrawFlower()を呼び出すと読みます。

    // 花の配列内の各花に対して
    for (let flower of flowers) {
      drawFlower(flower);
    }

コードは以下のようになるはずです:

試してみよう!

flowerPower()関数にパラメータを追加して、好きな数の花から簡単に始められるようにしてください。

例。

ステップ7:配列内の花を更新する

花の配列をテストしたので、次は萎れる効果を描画しましょう。花を制御するために配列を使用することの利点の1つは、各花の値を更新できることです。

  • 他のすべての関数の外側で、updateAndDrawFlowers()という関数を定義します:

    function updateAndDrawFlowers() {}
  • この関数は配列内の各花を見て、その花を描画します。

    for (let flower of flowers) {
       drawFlower(flower);
    }
  • forループ内で、萎れをシミュレートするために花オブジェクトのsizelifespanを減少させます。

    drawFlower()関数が花を描画した後、花のサイズを1%減少させることで萎れのアニメーション効果を追加します。現在のサイズに0.99を掛けて、その結果を花のsizeプロパティに戻すことで萎れ効果を作成します。次に、寿命を減少させ、その値を花のlifespan変数に保存します。以下の構文で乗算代入演算子デクリメント演算子を使用します:

    // 花の萎れ効果
    flower.size *= 0.99;
    
    // 寿命を減少させる
    flower.size -= 1; 
  • 花オブジェクトの寿命がゼロまたは負になったら、array.splice()メソッドを使用して配列から削除します。

    for (let flower of flowers) {
      // 花を描画する
      drawFlower(flower);
    
      // 花の萎れ効果
      flower.size *= 0.99;
    
      // 寿命を減少させる
      flower.lifespan -= 1; 
    
      if (flower.lifespan <= 0) {
        // 花のインデックスを保存する
        let i = flowers.indexOf(flower);
    
        // 萎れた花を削除する 
        flowers.splice(i, 1); 
      }
    }
  • draw()関数にupdateAndDrawFlowers()を追加します。

  • setup()からframeRate(1)の呼び出しを削除します。

コードは以下のようになるはずです:

試してみよう!

このチュートリアルを完了したら、クラスによるコードの整理チュートリアルに進んで、オブジェクト指向プログラミングについてさらに学ぶことをおすすめします。

ステップ8: mousePressed()を使って配列にさらに花を追加する

最後に、mousePressed()mouseXmouseYを使用して、キャンバスがクリックされるたびに花オブジェクトを flowers 配列に追加しましょう。

  • 他のすべての関数の外側に、mousePressed() 関数を書きます:

    function mousePressed() {
      let flower = createFlower();
    
      // xをmouseXに再割り当て
      flower.x = mouseX; 
      
      // yをmouseYに再割り当て
      flower.y = mouseY;
    
      // 花をflowers配列に追加
      flowers.push(flower);
    }

あなたのコードは以下のようになるはずです:

試してみよう!
  • マウスが押されたときに、mouseXmouseYの位置の周りに複数の花を追加します。()
  • 花の形や色を変えて実験してみましょう。()
  • 蜂や蝶のような新しい要素をガーデンに導入し、花とどのように相互作用するか見てみましょう。()

まとめ

データ構造ガーデンチュートリアルを完了おめでとうございます!

この旅を通じて、動的でインタラクティブなガーデンシミュレーションを作成するためのJavaScriptオブジェクトと配列の基本的な概念について学びました。配列を使用して、それぞれが独自のプロパティと動作を持つ複数のオブジェクトをエレガントかつ効率的に管理しました。これはプログラミングの世界で強力なスキルであり、より複雑でインタラクティブなアプリケーションへの扉を開きます。

次のステップ

もう一度、このチュートリアルを完了したことをお祝いします。実験を続け、コーディングを続け、そして最も重要なのは、学習と創造を楽しんでください!

リソース