14:ゲーム制作に役立つp5.play速習 Creative Coding p5.js

アリソンパリッシュによる

このチュートリアルでは、パオロ・ペデルチーニのp5.playライブラリを紹介します。このチュートリアルはいささか独断的で、p5.playを面白くする機能の多くを取り上げていません。このライブラリでできることの実感をつかむためにも、ぜひ公式サンプルリファレンスを調べてください。

p5.playライブラリは、ゲームやそのほかのインタラクティブアプリケーションの作成に役立つ、多くのオブジェクトや関数を提供します。p5.playが組み込むオブジェクトや関数は、まるでそれらがライブラリの中で前もってプログラムされていたかのように、p5.jsと一体化します。

インストール

p5.play.jsライブラリはここからダウンロードします。ファイルはp5.play-master.zipという名前でダウンロードされるので、このZIPファイルを展開(解凍)します。現れたフォルダのlibファルダ内にp5.play.jsファイルがあります。これを使用します。

p5.jsエディタでのインストールの要領は「13:外部ライブラリの使用 Creative Coding JavaScript」を参照してください。

p5.play.jsライブラリを設定したp5.jsエディタでのindex.htmlは次のようになります。

<!DOCTYPE html>
<html>

<head>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.3/p5.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.3/addons/p5.dom.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.3/addons/p5.sound.min.js"></script>
  <script src="p5.play.js"></script>
  <link rel="stylesheet" type="text/css" href="style.css">
  <meta charset="utf-8" />

</head>

<body>
  <script src="sketch.js"></script>
</body>

</html>

スプライト

”スプライト”とは、画面上での自分のサイズと位置を知っている、ゲーム(やそのほかのインタラクティブアプリケーション)のオブジェクトを言います。スプライトオブジェクトでは通常、プログラマーがスプライトの位置や軌道、外見を変更できるインタフェースや、たとえばスプライトが特定の位置(や別のスプライト)と交差しているかといったスプライトに関する質問をプログラマーが行えるインタフェースが公開されています。

1個のスプライト

p5.playでのスプライトの作成はcreateSprite()関数で行います。この関数は、自分自身のプロパティを調べたり変更できる多くの属性とメソッドを自身が持つスプライトオブジェクトを返します。

次のスケッチは、スプライトを1つ作成する簡単な例です。

let spr;

function setup() {
  createCanvas(400, 400);
  spr = createSprite( width/2, height/2, 40, 40);
  spr.shapeColor = color(255);
  spr.velocity.y = 0.5;
}

function draw() {
  background(50);
  drawSprites();
}

function mousePressed() {
  spr.position.x = mouseX;
  spr.position.y = mouseY;
}

createSprite()関数は、スプライトの位置と高さと幅の4つのパラメータを取ります。.shapeColor属性はスプライトを表す矩形のカラーを設定します。p5.playのスプライトを表示するには、draw()の終わりにdrawSprites()関数を追加する必要があります。

すべてのスプライトはposition属性とvelocity属性を持っています。position属性にもvelocity属性にもxとy属性があり、スプライトの位置とスピードの制御(XとY方向で)に使用できます。スピードにともなう位置の更新はみなさんに代わってp5.playライブラリが行うので、数学を用いる必要はありません。上記サンプルでは、マウスをクリックしない間、スプライトは定速で下方向に移動します。クリックすると、スプライトはすぐにクリック位置に移動し、そこから下方向への移動を開始します。

p5.play.createSprite()

createSprite ( x y width height ) Object

スプライトはp5.playの主要構成要素で、イメージやアニメーションが保持でき、位置や可視性といったプロパティのセットを持つ。スプライトは、ほかのスプライトやマウスとの衝突や重なりを判定するアクティブ領域を定義するコライダーを持つことができる。createSprite()で作成されたスプライトはallSpritesグループに追加され、ほかのすべてのスプライトの前面(手前)に来る深度が与えられる。

パラメータ

x Number – 最初のx座標
y Number – 最初のy座標
width Number – プレースホルダ矩形の幅。イメージか新しいコライダーが設定されるまでのコライダーの幅。
height Number – プレースホルダ矩形の高さ。イメージか新しいコライダーが設定されるまでのコライダーの高さ

戻り値

Object – 新しいスプライトインスタンス

Sprite.shapeColor

shapeColor Color

イメージかアニメーションが設定されていない場合、これがプレースホルダ矩形のカラーになる。

p5.play.drawSprites()

drawSprites ( group )

スプライトのグループを表示する。パラメータが指定されない場合には、スケッチ内のすべてのスプライトを描画する。描画する順番はスプライトの”depth”プロパティで決まる。

パラメータ

[group] Group オプション – 表示するスプライトのグループ

Sprite.position

position p5.Vector
スプライトのベクトル(x, y)としての位置

Sprite.velocity

velocity p5.Vector

スプライトのベクトル(x, y)としての速度。速度は、垂直方向と水平方向の成分に分割されたスピード。

移動するスプライト

前述したように、スプライトのスピードは.velocity.xと.velocity.yで直接設定できます。またスプライトのsetSpeed()メソッドを呼び出すと、そのスプライトに特定のスピードで特定の方向に移動するよう伝えることができます。次の例では、矢印キーを使ってスプライトを制御しています。

let spr;

function setup() {
  createCanvas(400, 400);
  spr = createSprite(width / 2, height / 3, 40, 40);
  spr.shapeColor = color(255);
}

function draw() {
  background(50);
  fill(255);
  noStroke();
  textAlign(CENTER, CENTER);
  text("矢印キーで移動。スペースキーで停止。", width / 2, height * 0.67);
  drawSprites();
}

function keyPressed() {
  if (keyCode == RIGHT_ARROW) {
    spr.setSpeed(1.5, 0);
  }
  else if (keyCode == DOWN_ARROW) {
    spr.setSpeed(1.5, 90);
  }
  else if (keyCode == LEFT_ARROW) {
    spr.setSpeed(1.5, 180);
  }
  else if (keyCode == UP_ARROW) {
    spr.setSpeed(1.5, 270);
  }
  else if (key == ' ') {
    spr.setSpeed(0, 0);
  }
  return false;
}

p5.jsのkey変数は英字でのみ動作します。矢印キーを判定するにはkeyCode変数を使用します。

Sprite.setSpeed()

setSpeed ( speed angle )
スプライトのスピードと方向を設定する。この呼び出しは現在の速度(velocity)を上書きする。方向が指定されない場合には、現在の方向が維持される。方向が指定されず現在の速度もない場合には、方向には現在の回転角度が使用される。

パラメータ

speed Number – スピード。スカラー値。
[angle] Number オプション – 度単位の方向

重力の追加は、毎フレーム下方向への一定の力を追加すること(.setSpeed()メソッドを使って)くらい簡単です。次のスケッチで描画するスプライトは、毎フレーム下方向に移動し、下端に当たると跳ね返ります。

let spr;

function setup() {
    createCanvas(400, 400);
    spr = createSprite(width / 2, height / 2, 40, 40);
    spr.shapeColor = color(255);
    spr.velocity.y = 0;
}

function draw() {
    background(50);
    if (spr.position.y >= height) {
        spr.velocity.y *= -1;
        // ”突き抜け”を避けるためheightに設定
        spr.position.y = height;
    }
    // 一定のスピードで落下(重力)
    spr.addSpeed(0.25, 90);
    drawSprites();
}

function mousePressed() {
    spr.position.y = mouseY;
}

Sprite.addSpeed()

addSpeed ( speed angle )
スプライトを、angleで定義された方向を押す。力は現在のvelocityに追加される。

パラメータ

speed Number – 追加するスピード、スカラー値
angle Number – 度単位の方向

マウスに追随

スプライトにマウスの後を追わせる方法はいくつもあります。1つめは、スプライトの位置を直接設定する方法です。

let spr;

function setup() {
    createCanvas(400, 400);
    spr = createSprite(width / 2, height / 2, 40, 40);
    spr.shapeColor = color(255);
}

function draw() {
    background(50);
    spr.position.x = mouseX;
    spr.position.y = mouseY;
    drawSprites();
}

また、またXとY速度(.velocity.xと.velocity.y)を、スプライトの位置とマウス位置の差に設定することで、スプライトの移動に少しタイムラグを追加することもできます。

let spr;

function setup() {
  createCanvas(400, 400);
  spr = createSprite(width / 2, height / 2, 40, 40);
  spr.shapeColor = color(255);
}

function draw() {
  background(50);
  spr.velocity.x = (mouseX - spr.position.x) * 0.2;
  spr.velocity.y = (mouseY - spr.position.y) * 0.2;
  drawSprites();
}

最後は、.attractionPoint()メソッドを使って、スプライトをマウス位置の方向に押す力を設定する方法です。

let spr;

function setup() {
    createCanvas(400, 400);
    spr = createSprite(width / 2, height / 2, 40, 40);
    spr.shapeColor = color(255);
    spr.rotateToDirection = true;
    spr.maxSpeed = 2;
    spr.friction = 0.01;
}

function draw() {
    background(50);
    if (mouseIsPressed) {
        spr.attractionPoint(0.5, mouseX, mouseY);
    }
    drawSprites();
}

このサンプルでは、オブジェクトの.maxSpeed属性(スプライトのスピードを、スプライトに作用する力に関係なく制御する)と、.friction属性(オブジェクトのスピードを毎フレーム、ゆっくり落とす乗数、摩擦係数)、.rotateToDirection属性(trueのとき、オブジェクトを、それが向いている方向に回転させる)も設定しています。

Sprite.attractionPoint()

attractionPoint ( magnitude pointX pointY )
スプライトをポイントに向けて押す。力は現在のvelocityに追加される。

パラメータ

magnitude Number – 追加するスピード、スカラー値
pointX Number – x座標、方向
pointY Number – y座標、方向

Sprite.friction

friction Number
摩擦要因。スプライトのスピードを減じる。摩擦は0に近くすべき(0.01など)。0は摩擦なしで、止まらない。1は完全な摩擦で、動かない。デフォルトは0。

Sprite.maxSpeed

maxSpeed Number
スプライトのスピードを、方向に関係なく制限する。正の値のみ。-1に設定すると、無制限になる。デフォルトは-1。

Sprite.rotateToDirection

rotateToDirection Boolean

ビジュアル要素(イメージやアニメーション)のrotationプロパティを、スプタイトの動きの方向にロックする。逆もまた同様。デフォルトはfalse。

マウスイベント

p5.playフレームワークのスプライトには、ユーザーがマウスを使ってスプライトとインタラクションしているかどうかを判定するための仕組みが組み込まれています。マウスのインタラクションを調べる方法には、イベントハンドラとブール値を値に取る属性の使用の2つがあります。

スプライトオブジェクトには、ユーザーのマウスの動きに対して自身の振る舞いを定義する関数が割り当てられる4つの属性があります。次のサンプルではその4つを全部使っています。

let spr1;
let spr2;

function setup() {
    createCanvas(400, 400);

    // スプライト1
    spr1 = createSprite(width / 2, height / 3, 100, 100);
    // スプライト1の色は白
    spr1.shapeColor = color(255);
    // マウスオーバーで2倍大きく
    spr1.onMouseOver = function() {
            this.scale = 2;
        }
        // マウスアウトで元の大きさに
    spr1.onMouseOut = function() {
        this.scale = 1;
    }

    // スプライト2
    spr2 = createSprite(width / 2, height * 0.67, 100, 100);
    // スプライト1の色は黒
    spr2.shapeColor = color(0);
    // マウスプレスで色をグレーに
    spr2.onMousePressed = function() {
            this.shapeColor = color(128);
        }
        // マウスリリースで元の黒に
    spr2.onMouseReleased = function() {
        this.shapeColor = color(0);
    }
}

function draw() {
    background(50);
    drawSprites();
}

4個の属性とは、以下を言います

  • onMouseOver (マウスカーソルがオブジェクト上に移動してきたとき)
  • onMouseOut (マウスカーソルがオブジェクト上から離れたとき)
  • onMousePressed (ユーザーがマウスボタンを押していて、マウスカーソルがオブジェクト上にあるとき)
  • onMouseReleased (onMousePressedイベントの後、ユーザーがマウスボタンを放したとき)

これらの属性に割り当てた関数は、指定されたイベントが発生するたびに実行されます。関数内部では、式thisがインタラクションの発生したオブジェクトを参照しています。これは、複数のオブジェクトに適用できるイベントハンドラの記述に役立ちます。詳細は後述します。

すべてのスプライトオブジェクトはまた、ブール値を持つmouseIsOver属性も持っています。mouseIsOver属性は、マウスがオブジェクト上にあるときはtrue、そうでないときはfalseになります。次のサンプルの2つのスプライトは、マウスがスプライトの上にあるときに応答します(2つめのスプライトの応答の振る舞いは、マウスボタンが押されている場合にのみ発生します)。

Sprite.scale

scale Number
スプライトのスケールを決める。例:2はビジュアルの元のサイズを2倍し、0.5は半分にする。拡大するとイメージはぼける可能性がある。デフォルトは1。

let spr1;
let spr2;

function setup() {
    createCanvas(400, 400);
    // スプライト1
    spr1 = createSprite(width / 2, height / 3, 100, 100);
    spr1.shapeColor = color(255);
    spr1.mouseActive = true;
    // スプライト2
    spr2 = createSprite(width / 2, height * 0.67, 100, 100);
    spr2.shapeColor = color(0);
    spr2.mouseActive = true;
}

function draw() {
    background(50);
    // スプライト1にマウスが重なったら背景をグレーに
    if (spr1.mouseIsOver) {
        background(100);
    }
    // スプライト1にマウスが重なり、かつマウスボタンが押されているなら
    // スプライト2を回転させる
    if (spr2.mouseIsOver && mouseIsPressed) {
        spr2.rotation += 4;
    }
    drawSprites();
}

このサンプルでは、.rotation属性の使用方法も覚えておいてください。.rotation属性はスプライトの現在の回転を設定します(度単位)。

Sprite.mouseActive

mouseActive Boolean
trueに設定すると、スプライトはマウスの状態を追跡する。mouseIsPressedとmouseIsOverプロパティが更新される。注意:onMouseReleasedまたはonMousePressedに関数が割り当てられると、自動的にtrueに設定される。デフォルトはfalse。

Sprite.mouseIsOver

mouseIsOver Boolean
マウスがスプライトのコライダー上にあるときtrue。読み取り専用。

Sprite.mouseIsPressed

mouseIsPressed Boolean
マウスがスプライトのコライダー上で押されているときtrue。読み取り専用。

Sprite.rotation

rotation Number
ビジュアル要素(イメージやアニメーション)の度単位の回転。注意:これは移動の方向ではない。getDirectionを参照。デフォルトは0。

複数のスプライト

createSprite()関数は、好きなだけ何度でも呼び出すことができます。p5.playフレームワークは、みなさんが追加したすべてのスプライトを、舞台裏で追跡します(したがって、スプライトを保持するデータ構造を自分で作成する必要はありません)。次の例では、ユーザーがマウスをクリックするたびに、新しいスプライトを作成するコードをmousePressed()関数に記述しています。

function setup() {
  createCanvas(400, 400);
}

function draw() {
  background(50);
  drawSprites();
}
// mousePressed()はp5.jsの関数
function mousePressed() {
  var spr = createSprite(width / 2, height / 2, random(10, 50), random(10, 50));
  spr.shapeColor = color(255);
  spr.velocity.y = random(3);
  spr.velocity.x = random(-3, 3);
  spr.position.x = mouseX;
  spr.position.y = mouseY;
  spr.friction = 0.005;
  spr.life = 120;
}

ここでは.life属性の使用に注目してください。.life属性は、そのスプライトがp5.playフレームワークによって自動的に消去されるまで”生きつづける”、最大フレーム数です。

Sprite.life

life Number
自身が除去されるサイクル。カウントダウンの初期化に設定すると、描画サイクルごとにこのプロパティが1単位ずる減少する。0でsprite.remove()を呼び出す。-1に設定すると無効になる。デフォルトは-1。

p5.playフレームワーク自体が実行する変更以外に、作成したスプライトに変更を適用したい場合には、draw()内ですべてのスプライトを対象にして繰り返し処理を行う必要があります。p5.playには、スケッチ内のアクティブなスプライト全部を含むallSpritesという名前のビルトイン配列があります。

次の例では、このallSprites変数を使って、mousePressed()でシーンに追加した各スプライトに”重力”(一定の下方向への力)を適用しています。また最初のifステートメントでは、スプライトがスケッチの高さを超えたかどうかを調べ、超えた場合には”跳ね返り”を生じさせています。2つめのifステートメントでは、X方向でのスケッチの範囲を超えたスプライトを削除しています。

function setup() {
    createCanvas(400, 400);
    textSize(32);
    textAlign(RIGHT, TOP);
    fill(255);
}

function draw() {
    background(50);
    for (var i = 0; i < allSprites.length; i++) {
        // 重力
        allSprites[i].addSpeed(0.1, 90);
        if (allSprites[i].position.y > height) {
            allSprites[i].velocity.y *= -1;
        }
        // スプライトを削除するコードは、ループの最後に記述する
        if (allSprites[i].position.x > width ||
            allSprites[i].position.x < 0) {
            allSprites[i].remove();
        }
    }
    text("スプライトの数: " + allSprites.length, width - 10, 10);
    drawSprites();
}

function mousePressed() {
    var spr = createSprite(width / 2, height / 2, random(10, 50), random(10, 50));
    spr.shapeColor = color(255);
    spr.velocity.y = random(3);
    spr.velocity.x = random(-3, 3);
    spr.position.x = mouseX;
    spr.position.y = mouseY;
}

p5.play.allSprites

allSprites Group
スケッチの全部のスプライトを含むGroup

Sprite.remove()

remove ()
スケッチからそのスプライトを削除する。削除されたスプライトはもう描画されず、更新されない。

複数のスプライトで発生するイベント

複数のスプライトに同じイベントハンドラを設定すると、同じイベントの発生時に同じ関数を実行することができます。次の例では、着色したスプライトをマウスでなぞると、そのスプライトがスケッチから削除され、スコアが1アップします。

let score = 0;

function setup() {
    createCanvas(400, 400);

    fill(255);
    noStroke();
    textSize(72);
    textAlign(CENTER, CENTER);

    for (var i = 0; i < 10; i++) {
        // ランダムなサイズでランダムな位置にスプライトを10個作成
        const spr = createSprite(random(width), random(height), random(10, 50), random(10, 50));
        const randomColor = color(random(255), random(255), random(255));
        spr.shapeColor = randomColor;
        // スプライトのonMouseOverにイベントハンドラを設定
        // => 10個のスプライト全部で、マウスオーバー時に同じ関数が呼び出せる。
        spr.onMouseOver = function() {
            score += 1;
            this.remove();
            // thisはこのスプライトを参照する
            console.log(this);
        }
    }
}

function draw() {
    background(50);
    drawSprites();
    if (score < 10) {
        text(score, width / 2, height / 2);
    }
    else {
        text("you win!", width / 2, height / 2);
    }
}

マウスでどのスプライトをなぞっても同じアクションが実行できるのは、forループで設定しているスプライトにイベントハンドラを追加しているからです。ここで重要なことは、thisがforループで作成しているスプライトを参照する点です。当該スプライトをthisで参照することで、各スプライトに共通する振る舞いを与えることができます。

スプライトのグループ

Groupオブジェクトを使用すると、同種のスプライトをまとめて扱いたいときに重宝します。GroupオブジェクトはJavaScriptの配列を拡張したもので、配列のメソッドやプロパティはそのまま利用でき、その上、独自の拡張機能が使用できます。

次の例では、雲用と鳥用のGroupを2つ作成し、それに雲と鳥のスプライトを追加して、draw()内でforループを使って、Groupごとに異なる振る舞いを与えています。

let clouds;
let birds;

function setup() {
    createCanvas(400, 400);
    // 雲グループ
    clouds = new Group();
    // 鳥グループ
    birds = new Group();

    // 雲スプライトを10個作成し、雲グループに追加する。
    for (var i = 0; i < 10; i++) {
        var c = createSprite(random(width), random(height), random(25, 100), random(25, 100));
        c.shapeColor = color(random(200, 255));
        clouds.add(c);
    }

    // 鳥スプライトを5個作成し、鳥グループに追加する。
    for (var i = 0; i < 5; i++) {
        var b = createSprite(random(width), random(height), random(10, 50), random(5, 25));
        // スプライトごとに外見と振る舞いを少し変える
        b.shapeColor = color(255, 0, random(255));
        b.friction = random(0.03, 0.01);
        b.maxSpeed = random(1, 4);
        // 頭を先に向けて移動
        b.rotateToDirection = true;
        birds.add(b);
    }
}

function draw() {
    // 青い空
    background(0, 150, 240);

    // 雲グループの雲スプライトを繰り返し処理
    for (var i = 0; i < clouds.length; i++) {
        // 各雲スプライトを、そのスプライトの幅の1%だけ右に移動
        clouds[i].position.x += clouds[i].width * 0.01;
        // スケッチの右端まで到達したら、左端に移動 => 再び右に現れ移動を開始する
        if (clouds[i].position.x > width) {
            clouds[i].position.x = 0;
        }
    }
    // 鳥グループの鳥スプライトを繰り返し処理
    for (var i = 0; i < birds.length; i++) {
        // マウスに追随させる。
        // 鳥スプライトはrotateToDirectionがtrueに設定されているので、”頭”をマウスの方向に向けて移動する。
        birds[i].attractionPoint(0.2, mouseX, mouseY);
    }
    drawSprites();
}

Group

p5.playのGroupは、同様の振る舞いを持つスプライトの集まり。たとえば、バックグラウンドにあるすべてのスプライトを含むGroupや、プレイヤーを攻撃してくるすべてのスプライトを含むGroupなど。Groupは”拡張された”配列で、配列の全プロパティを継承している(group.lengthなど)。Groupが含むのは参照なので、あるスプライトを複数のGroupに含めることができる。Groupを消去してもスプライト自体には影響しない。sprite.remove()は、そのスプライトが属する全グループからそのスプライトを削除する。

Group.add()

add ( s )
スプライトをグループに追加する。

パラメータ

s Sprite – 追加するスプライト

衝突

たとえば、ミサイルを宇宙船に命中させたい場合など、ゲームの制作にスプライト同士の衝突判定は必需品です。p5.playでは、重なり状態にあるかどうかを調べるoverlap()と、衝突元のスプライトを衝突していない位置に移動させるcollide()メソッド、衝突相手の方を移動させるdisplace()メソッドで衝突判定が行えます。

次のスケッチはoverlap()メソッドの使用例で、マウスに追随する小さな矩形が大きな黒い矩形と重なると、大きな矩形の色が白に変わります。

let spr1;
let spr2;

function setup() {
    createCanvas(400, 400);
    // 大きな黒いスプライト1をセンターに作成
    spr1 = createSprite(width / 2, height / 2, 150, 150);
    spr1.shapeColor = color(0);
    // マウスに追随する小さなスプライト2
    spr2 = createSprite(0, 0, 50, 50);
    spr2.shapeColor = color(128);
}

function draw() {
    background(50);
    // スプライト2を少し遅れてマウスに追随させる
    spr2.velocity.x = (mouseX - spr2.position.x) * 0.2;
    spr2.velocity.y = (mouseY - spr2.position.y) * 0.2;
    // スプライト2がスプライト1と重なっているなら
    if (spr2.overlap(spr1)) {
        // スプライト1を白く
        spr1.shapeColor = color(255);
    // 重なっていないなら
    }
    else {
        // スプライト1を黒く
        spr1.shapeColor = color(0);
    }
    drawSprites();
}

Sprite.overlap()

overlap ( target callback ) Boolean

スプライトが、別のスプライトかグループに重なっているかどうかを調べる。このチェックはコライダーを使って実行される。コライダーが設定されていない場合、イメージかアニメーションのボックスから自動的に作成される。

コールバック関数には、重なりが発生したときの追加的な操作の実行が指定できる。ターゲットがグループの場合には、コールバック関数は、グループのスプライトごとの重なりに対して呼び出される。コールバック関数のパラメータは、現在のスプライトと衝突中の相手スプライト。

パラメータ

target Object – 重なりの対象とする相手スプライトかグループ
[callback] Function オプション – 重なり状態にある場合に呼び出される関数

戻り値

Boolean – 重なり状態にある場合true

次のスケッチはcollide()メソッドの使用例で、小さな矩形はマウスに追随して移動しますが、大きな黒い矩形とは決して重なりません。

let spr1;
let spr2;

function setup() {
    createCanvas(400, 400);
    spr1 = createSprite(width / 2, height / 2, 100, 100);
    spr1.shapeColor = color(0);
    spr2 = createSprite(0, 0, 50, 50);
    spr2.shapeColor = color(128);
}

function draw() {
    background(50);
    //スプライト2を少し遅れてマウスに追随
    spr2.velocity.x = (mouseX - spr2.position.x) * 0.2;
    spr2.velocity.y = (mouseY - spr2.position.y) * 0.2;
    // スプライト2がスプライト1に衝突したら、スプライト2を衝突していない位置に移す
    spr2.collide(spr1);
    drawSprites();
}

collide()

collide ( target callback ) Boolean

スプライトが、別のスプライトかグループに重なっているかどうかを調べる。重なりが発生している場合には、現在のスプライトが、衝突相手のスプライトによって、衝突していない最も近い位置に再配置される。このチェックはコライダーを使って実行される。コライダーが設定されていない場合、イメージかアニメーションのボックスから自動的に作成される。

コールバック関数には、衝突が発生したときの追加的な操作の実行が指定できる。ターゲットがグループの場合には、コールバック関数は、グループのスプライトごとの衝突に対して呼び出される。コールバック関数のパラメータは、現在のスプライトと衝突中の相手スプライト。

パラメータ

target Object – 衝突の対象とする相手スプライトかグループ
[callback] Function オプション – 重なり状態にある場合に呼び出される関数

戻り値

Boolean – 重なり状態にある場合true

次のスケッチはdisplace()メソッドの使用例で、小さな矩形はマウスに追随して移動し、衝突すると大きな黒い矩形を押して動かします。

let spr1;
let spr2;

function setup() {
    createCanvas(400, 400);
    spr1 = createSprite(width / 2, height / 2, 100, 100);
    spr1.shapeColor = color(0);

    spr2 = createSprite(0, 0, 50, 50);
    spr2.shapeColor = color(128);
}

function draw() {
    background(50);
    //スプライト2を少し遅れてマウスに追随
    spr2.velocity.x = (mouseX - spr2.position.x) * 0.2;
    spr2.velocity.y = (mouseY - spr2.position.y) * 0.2;
    // スプライト2がスプライト1の位置を決める
    spr2.displace(spr1);
    drawSprites();
}

Sprite.displace()

displace ( target callback ) Boolean

スプライトが、別のスプライトかグループに重なっているかどうかを調べる。重なりが発生している場合には、現在のスプライトが衝突相手のスプライトを、重なっていない最も近い位置に再配置する。このチェックはコライダーを使って実行される。コライダーが設定されていない場合、イメージかアニメーションのボックスから自動的に作成される。

コールバック関数には、衝突が発生したときの追加的な操作の実行が指定できる。ターゲットがグループの場合には、コールバック関数は、グループのスプライトごとの衝突に対して呼び出される。コールバック関数のパラメータは、現在のスプライトと衝突中の相手スプライト。

パラメータ

target Object – 衝突の対象とする相手スプライトかグループ
[callback] Function オプション – 重なり状態にある場合に呼び出される関数

戻り値

Boolean – 重なり状態にある場合true

グループ同士の衝突

Group同士の衝突でも、collide()とdisplace()が、Spriteと同じように使用できます。これは、スプライトをグループでまとめていても、スプライト同士の衝突判定がグループ間で行えるということです。

let walls;
let boxes;
let player;

function setup() {
    createCanvas(400, 400);
    // 壁グループ
    walls = new Group();
    // 箱グループ
    boxes = new Group();
    // プレイヤーは白
    player = createSprite(100, 100, 40, 40);
    player.shapeColor = color(255);

    // ランダムな位置にランダムな大きさのグレーを壁を5個作成
    for (var i = 0; i < 5; i++) {
        var w = createSprite(random(125, width - 125), (height / 5) * i, random(10, 100), random(10, 100));
        w.shapeColor = color(125);
        // 壁スプライトを壁グループに追加
        walls.add(w);
    }

    // ランダムな位置に赤い箱シェイプを4個作成
    for (var i = 0; i < 4; i++) {
        var b = createSprite(random(50, 100), random(100, height - 100), 25, 25);
        b.shapeColor = color(255, 0, 0);
        // 箱スプライトを箱グループに追加
        boxes.add(b);
    }
}

function draw() {
    background(50);
    // 白い矩形を少し遅れてマウスに追随
    player.velocity.x = (mouseX - player.position.x) * 0.1;
    player.velocity.y = (mouseY - player.position.y) * 0.1;
    // 白い矩形は壁グループと衝突すると、衝突した壁スプライトによって位置を変えられる。
    player.collide(walls);
    // 白い矩形は箱グループと衝突すると、衝突した箱スプライトの位置を変える。
    player.displace(boxes);

    // 箱グループが壁グループと衝突すると、箱グループの衝突した箱スプライトが、衝突した壁スプライトによって位置を変えられる。
    boxes.collide(walls);
    // 箱グループが箱グループと衝突すると、箱グループの衝突した箱スプライトが、衝突した箱スプライトの位置を変える
    boxes.displace(boxes);
    drawSprites();
}

Group.collide()

collide ( target callback ) Boolean

グループが、別のグループかスプライトに重なっているかどうかを調べる。重なりが発生している場合には、グループ内のスプライトが、衝突相手によって、重なりの発生していない最も近い位置に再配置される。このチェックはコライダーを使って実行される。コライダーが設定されていない場合、イメージかアニメーションのボックスから自動的に作成される。

コールバック関数には、重なりが発生したときの追加的な操作の実行が指定できる。コールバック関数は、1スプライトごとの重なりに対して呼び出される。コールバック関数のパラメータは、現在のグループのメンバーととパラメータとして渡されたほかのスプライト。

パラメータ

target Object – 衝突の対象とする相手スプライトかグループ
[callback] Function オプション – 重なり状態にある場合に呼び出される関数

戻り値

Boolean – 重なり状態にある場合true

Group.displace()

displace ( target callback ) Boolean

グループが、別のグループかスプライトに重なっているかどうかを調べる。重なりが発生している場合には、グループ内のスプライトが衝突相手を、重なっていない最も近い位置に再配置する。このチェックはコライダーを使って実行される。コライダーが設定されていない場合、イメージかアニメーションのボックスから自動的に作成される。

コールバック関数には、重なりが発生したときの追加的な操作の実行が指定できる。コールバック関数は、1スプライトごとの重なりに対して呼び出される。コールバック関数のパラメータは、現在のグループのメンバーとパラメータとして渡されたほかのスプライト。

パラメータ

target Object – 衝突の対象とする相手グループかスプライト
[callback] Function オプション – 重なり状態にある場合に呼び出される関数

戻り値

Boolean – 重なり状態にある場合true

衝突のコールバック

上のp5.playリファレンスからの引用で分かるように、overlap()とcollide()、displace()メソッドには、2つめのパラメータとしてコールバック関数が指定できます。次の例ではoverlap()にコールバック関数を指定して、マウスに追随する白い矩形がコインに模した黄色い矩形と重なったときに、コインのスプライトを削除し、スコアを1足しています。

let coins;
let player;
let score = 0;

function setup() {
    createCanvas(400, 400);
    // スコア表示用の設定
    fill(255);
    noStroke();
    textSize(72);
    textAlign(CENTER, CENTER);

    coins = new Group();
    // 黄色の小さな矩形のコインスプライトを10個作成して、コイングループに追加
    for (var i = 0; i < 10; i++) {
        var c = createSprite(random(100, width - 100), random(100, height - 100), 10, 10);
        c.shapeColor = color(255, 255, 0);
        coins.add(c);
    }
    // プレイヤー用の白い矩形
    player = createSprite(50, 50, 40, 40);
    player.shapeColor = color(255);
}

function draw() {
    background(50);
    // プレイヤーを少し遅れてマウスに追随
    player.velocity.x = (mouseX - player.position.x) * 0.1;
    player.velocity.y = (mouseY - player.position.y) * 0.1;

    // プレイヤーがコイングループと重なったら、
    player.overlap(coins, function(player, coin) {
        // 重なったそのコインを削除
        coin.remove();
        // スコアを1増やす
        score += 1;
    });
    drawSprites();
    if (coins.length > 0) {
        text(score, width / 2, height / 2);
    }
    else {
        text("you win!", width / 2, height / 2);
    }
}

イメージとアニメーション

スプライトには、それを表す”顔”として画像を使用することができます。画像を使用するにはpreload()内でloadImage()関数を使って画像を読み込み、スプライトを作成して、スプライトのaddImage()メソッドを使ってイメージを追加します。

次の例では、ネコのイメージをスプライトに追加し、マウスの押し下げ中に回転させています。

let kitty;
let kittyImg;

// 画像ファイルはpreload()で読み込んでおく
function preload() {
    kittyImg = loadImage('kitty_transparent.png');
}

function setup() {
    createCanvas(400, 400);
    // スプライトのサイズは.pngファイズの幅と高さにする
    kitty = createSprite(0, 0, kittyImg.width, kittyImg.height);
    // スプライトにイメージを追加 => 見かけは画像に見えるが実体はスプライト
    kitty.addImage(kittyImg);
}

function draw() {
    background(255);
    // スプライトをマウスの追随
    kitty.position.x = mouseX;
    kitty.position.y = mouseY;
    // マウスの押し下げ中は、スプライトを回転させる
    if (mouseIsPressed) {
        kitty.rotation += 2;
    }
    drawSprites();
}

Sprite.addImage()

addImage ( label img )

スプライトにイメージを追加する。1つイメージは1フレームのアニメーションと見なされる。画像は、p5.jsのloadImage()関数を使って、preload()内で読み込んでおく。アニメーションを変更するには、識別ラベル(文字列)が必要。イメージはスプライト内に保持されるが、Sprite.changeAnimation(label)が呼び出されるまで、必ずしも表示されるとは限らない。

使い方

sprite.addImage(label, image);
sprite.addImage(image);
イメージだけが渡された場合には、ラベルは指定されない。

パラメータ

label String | p5.Image – ラベルまたはイメージ
[img] p5.Image オプション – イメージ

アニメーション

p5.playサンプルから引用したアニメーション

let spr;
let anim;

function preload() {
    // 連番が振られた一連の画像からAnimationオブジェクトを作成するs
    anim = loadAnimation("asterisk_normal0001.png", "asterisk_normal0002.png", "asterisk_normal0003.png");
    //console.log(anim);
}

function setup() {
    createCanvas(400, 400);
    spr = createSprite(width / 2, height / 2);
    // スプライトにアニメーションを追加
    spr.addAnimation("default", anim);
}

function draw() {
    background(255);
    spr.position.x = mouseX;
    spr.position.y = mouseY;
    if (mouseIsPressed) {
        spr.rotation -= 2;
    }
    drawSprites();
}

Animation

Animationオブジェクトは、連続して表示できる一連のイメージ(p5.Image)を含む。すべてのファイルはpngイメージでなくてはならない。スケッチのルートからのディレクトリと拡張子.pngを含める必要がある。

スプライトはラベルを付けた複数のアニメーションを持つことができる(Sprite.addAnimationSprite.changeAnimationを参照)が、アニメーションは単独でも使用できる。

アニメーションは、連番でつながった一連のファイル名を渡すか、連番を振った一連のファイル名の最初と最後のファイル名(ファイル数はいくつでもよい)を渡すかどちらかの方法で作成できる。p5.playはその連続パターンを見つけようとする。

たとえば、与えられたファイル名が”data/file0001.png”と”data/file0005.png”の場合、画像”data/file0003.png”と”data/file0004.png”も読み込まれる。

p5.play.loadAnimation()

loadAnimation ( sprite )

アニメーションを読み込む。通常は、スケッチのpreload()関数内で使用する。

パラメータ

sprite Sprite – 表示するスプライト

Sprite.addAnimation()

addAnimation ( label animation )

スプライトにアニメーションを追加する。アニメーションは、p5.jsのloadImage()関数を使って、preload()内で読み込んでおく。アニメーションを変更するには、識別ラベル(文字列)が必要。アニメーションはスプライト内に保持されるが、Sprite.changeAnimation(label)が呼び出されるまで、必ずしも表示されるとは限らない。

使い方

sprite.addAnimation(label, animation);

別の使い方:
sprite.addAnimation(label, firstFrame, lastFrame);
sprite.addAnimation(label, frame1, frame2, frame3…);

パラメータ

label String – アニメーション識別子
animation Animation – プリロード済みのアニメーション

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA