7_2:速度と方向 p5.js JavaScript

右に少しずつ移動する

左から右に少しずつ、移動するモーションのコードは次のように記述できます。

// x軸方向への移動
// シェイプの半径
const radius = 40;
// シェイプの最初のx値
let x = -40;
// スピード(速度)
const vx = 0.5;

function setup() {
    createCanvas(240, 120);
    ellipseMode(RADIUS);
    angleMode(DEGREES);
}

function draw() {
    background(0);
    // 1フレーム中(= draw()関数が1回実行される間 = 1/60秒)に0.5移動する
    x += vx;
    // 右に口を開いた円
    arc(x, 60, radius, radius, 30, 330);
}

変数xは描画する円のx位置、vxは速度(スピード)です。速度というと、「速度 = 距離 / 時間」という公式が思い浮かび、面倒な印象があるかも知れませんが、ここでは下図のように考えることができます。

図の四角形は描画するキャンバスで、幅は240です。ここにはdraw()関数が1/60秒かけて、背景色やシェイプを描画するので、フレーム(映画フィルムのコマ)と見なすことができます。

左のフレームでdraw()は黄色の円をx=10の位置に描画しています。draw()は1回の描画が終わったら、次の描画に移ります。その描画では、真ん中のフレームのように、黄色の円を0.5だけ右に描画します。そして1/60秒後の次の描画では黄色の円をさらに0.5だけ右に描画します。これをずっと連続します。

x = 10;
x = 10 + 0.5 = 10.5; => 0.5だけ右に移動
x = 10.5 + 0.5 = 11; => 0.5だけ右に移動

ここでは、1/60秒の間に、0.5だけ右に移動する値を速度と見なすことができます(単位時間当たりの変化量)。したがって、0.5をもっと大きな値に変更すると、円が右に移動するスピードはアップします。

外に出たら戻る

前の例では、右へ進んだ後、キャンバスの外に出たらそれっきりなので、元に戻してみましょう。そのためには円の位置を常時監視し、円が外に出たタイミングを知る必要があります。監視する場所は1/60秒の頻度で呼び出されるdraw()関数が適切です。

function draw() {
        background(0);
        x += vx;
        if (x > width - radius) {
            print('シェイプ右端が画面右端を超えた');
        }

p5.jsには、シェイプがキャンバスの右端を超えたタイミングを教えてくれる便利な関数はないので、ifステートメントを使って調べます。ここではまず、「シェイプ右端が画面右端を超えたかどうか」(x > width – radius)を調べています。width – radiusはキャンバスの右端に円の右端が接する位置なので、これより円のx位置が大きくなると、print(‘シェイプ右端が画面右端を超えた’)が呼び出されつづけます。

同様に、x > widthは「シェイプセンターが画面右端を超えた」ということであり、x > width + radiusは「シェイプ左端が画面右端を超えた」ということです。

「シェイプ左端が画面右端を超えた」ら、「シェイプを元の位置に戻す」といくことは、

if (x > width + radius) {
    print('シェイプ左端が画面右端を超えた');
    // -半径分、画面左外に移す
    x = -40;
}

ということです。すると、x > width + radiusという条件は満たされなくなって、円は-40の位置から再び右に移動を始めます。

// スクリーンラッピング
// シェイプの半径
const radius = 40;
// シェイプの最初のx値
let x = -40;
// スピード(速度) ->
const vx = 0.5;

function setup() {
    createCanvas(240, 120);
    ellipseMode(RADIUS);
    angleMode(DEGREES);
}

function draw() {
    background(0);
    x += vx;
    if (x > width - radius) {
        //print('シェイプ右端が画面右端を超えた');
    }
    if (x > width) {
        //print('シェイプセンターが画面右端を超えた');
    }
    if (x > width + radius) {
        print('シェイプ左端が画面右端を超えた');
        // -半径分、画面左外に移す
        x = -radius;
    }
    arc(x, 60, radius, radius, 30, 330);
}

左右の端で反転

右へ進むシェイプがキャンバスの右端に到達したら向きを左に変えて進み、左端に到達したら右に向きを変えて進む、というコードは次のように記述できます。

// 跳ね返り
const radius = 40;
let x = -radius
const vx = 0.5;
// 向きの変数、最初は右
let direction = 1;

let p1;
let p2;

function setup() {
    createCanvas(240, 120);
    ellipseMode(RADIUS);
    angleMode(DEGREES);
    p1 = createP();
    p2 = createP();
}

function draw() {
    background(0);
    // vxにdirectionを掛ける。
    // directionが1のときは結果に影響はないが、directionが-1のときは結果がマイナス値になる、
    x += vx * direction;

    // シェイプ右端が画面右端を超えたら
    if (x + radius > width) {
        // 円を、キャンバス右端より半径分だけ左に強制的に戻す
        x = width - radius;
        // 向きを反転 1なら-1に、-1なら1にする
        direction *= -1;
        // シェイプの左端が画面左端を超えたら
    }
    else if (x - radius < 0) {
        // 円を、キャンバス左端より半径分だけ右に強制的に戻す
        x = 0 + radius; // 0は本来は不要
        // 向きを反転 1なら-1に、-1なら1にする
        direction *= -1;
    }
    // 向きによって描画物を変える
    if (direction === 1) {
        // 右が開いた白の円
        fill(255);
        arc(x, 60, radius, radius, 30, 330);
    }
    else {
        // 左が開いた黄色の円
        fill(255, 255, 0);
        arc(x, 60, radius, radius, 210, 510);
    }
    p1.html('direction : ' + direction);
    p2.html('x : ' + x);
}

次のリンクをクリックすると、実際の動作が確認できます。「跳ね返り

ここでは新たにdirection変数を作成しています。これには最初1を代入して、これで右方向を表すことにします。これをvxに掛けます。すると、directionが1のときはこれまでと変わりませんが、-1のときにはvxが-vxに変わります。これは左に進むということです。

x += vx * direction;

後は、向きを反転させたいタイミング(シェイプ右端が画面右端を超えときとシェイプの左端が画面左端を超えとき)で、directionに-1を掛けます(そのときのdirectionに-1を掛けた値をdirectionに代入します)。するとdirectionは1なら-1に、-1なら1に変化します。

direction *= -1;

上記のサンプルでは、directionとxの値を<p>要素のテキストに書き出しているので、directionが1から-1に、また1から-1に変化するタイミングと、1のときにはxは増加し、-1のとき減少することが分かります。

コメントを残す

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

CAPTCHA