9_1:p5.play 「ポン」 ゲームサンプル

「ポン」(Pong)は「ゲームカタログ@Wiki」によると、次のように説明されています。

システム
  • 対戦プレイ専用
  • 互いにダイヤル状のツマミ(パドル)を使って縦長のバー(自機)を操作し、ドット(ボール)を弾きあってプレイする
  • バーは上下にしか動かす事が出来ない
  • バーで弾かれたボールは一定の法則に基づいて角度を変えて弾かれる
  • ボールが相手のバーを超え、センターラインを突破すると勝利となり、スコアが加算される
  • 現代風に例えるとエアホッケーのビデオゲーム版といった感じ

以下は、このPongもどきの、p5.playのサンプルにある「Pong」を見ていきます(なお、細かな部分でコードを書き替えています)。

// 「ポン」(卓球ゲーム)もどき
// マウスで両方のパドルを走査する

let leftPaddleSp, rightPaddleSp, ballSp, wallTopSp, wallBottomSp;
const MAX_SPEED = 10;

function setup() {
    createCanvas(800, 400);
    //frameRate(6);
    const w = 10;
    const h = 100;
    const offset = 30;

    // 左のパドルスプライト
    leftPaddleSp = makeSprite(offset, height / 2, w, h, true, color(255, 0, 0));
    // 右のパドルスプライト
    rightPaddleSp = makeSprite(width - offset, height / 2, w, h, true, color(255, 0, 255));
    // 上の壁スプライト
    wallTopSp = makeSprite(width / 2, -10, width, offset, true, color(0, 255, 0));
    // 下の壁スプライト
    wallBottomSp = makeSprite(width / 2, height + 10, width, offset, true, color(0, 255, 0));
    // ボールスプライト
    ballSp = makeSprite(width / 2, height / 2, 10, 10, false, color(255));
    // 速くなりすぎないように制限を設ける
    ballSp.maxSpeed = MAX_SPEED;
    // ボールは最初、キャンバス中央から左へ進む
    ballSp.setSpeed(MAX_SPEED, -180);
}

// スプライトを作成し、与えられた引数でプロパティを設定したスプライトを返す
function makeSprite(xpos, ypos, w, h, isImmovable, col) {
    const sp = createSprite();
    sp.width = w;
    sp.height = h;
    sp.position.x = xpos;
    sp.position.y = ypos;
    sp.immovable = isImmovable;
    sp.shapeColor = col;
    return sp;
}

function draw() {
    background(0);
    update();
    drawSprites();
}

function update() {
    // パドルがキャンバスから出ないように、上下の動きを制限し、
    // 右パドルを左パドルの動きに同期させる。
    leftPaddleSp.position.y = constrain(mouseY, leftPaddleSp.height / 2, height - leftPaddleSp.height / 2);
    rightPaddleSp.position.y = constrain(mouseY, leftPaddleSp.height / 2, height - leftPaddleSp.height / 2);

    // ボールは上の壁に当たったら跳ね返る
    ballSp.bounce(wallTopSp);
    // ボールは下の壁に当たったら跳ね返る
    ballSp.bounce(wallBottomSp);

    // 入射角=反射角とする => ballSp.getDirection()
    // 「反射の法則」 https://exam.fukuumedia.com/rika1-13/#i-3
    // ただし、ボールの芯とパドルの芯のずれが大きいと、反射角も大きくなる

    // ボールが左パドルに当たったら
    if (ballSp.bounce(leftPaddleSp)) {
        // ボールの芯とパドルの芯のずれ。
        const swing = (ballSp.position.y - leftPaddleSp.position.y) / 3;
        // 左パドルの場合、角度は時計回りに大きくなるので、角度を大きくするにはswingを足す
        ballSp.setSpeed(MAX_SPEED, ballSp.getDirection() + swing);
        print(ballSp.getDirection())
    }

    // ボールが右パドルに当たったら
    if (ballSp.bounce(rightPaddleSp)) {
        const swing = (ballSp.position.y - rightPaddleSp.position.y) / 3;
        // 右パドルの場合、角度は反時計回りに大きくなるので、角度を大きくするにはswingを引く
        ballSp.setSpeed(MAX_SPEED, ballSp.getDirection() - swing);
    }

    // ボールがキャンバス左端から外に出たら、真ん中に再配置し右へ動く
    if (ballSp.position.x < 0) {
        ballSp.position.x = width / 2;
        ballSp.position.y = height / 2;
        ballSp.setSpeed(MAX_SPEED, 0);
    }
    // ボールがキャンバス右端から外に出たら、真ん中に再配置し左へ動く
    if (ballSp.position.x > width) {
        ballSp.position.x = width / 2;
        ballSp.position.y = height / 2;
        ballSp.setSpeed(MAX_SPEED, 180);
    }
}

次のリンクのクリックで実際にゲームサンプルがプレイできます。「ポン

スプライトは左右のパドル2つと、上下の壁、ボールの合計5つです。ボールは上と下の壁に当たったら跳ね返ります。また、パドルに当たっても跳ね返ります。

ボールとパドルとの跳ね返りは、「反射の法則」と呼ばれる方法で表現できます。これは、入って来る入射角と出て行く反射角が等しくなる、という法則です。

p5.play.jsのSprite.bounce()メソッドにも、この法則が実装されていると思われるので、たとえば20度の入射角で入って来たボールは、何もしなくても、Sprite.bounce()メソッドの働きによって、20度の反射角で出ていきます。下図はその説明です。

たとえば次のコードで、ボールスプライトを160度の方向へ移動させたとします。160度というのは、X軸方向、つまり真右を0度として時計回りに160度回転した方向です。

ballSp.setSpeed(MAX_SPEED, 160);

このボールがパドルに当たると、そのときのballSp.getDirection()は20になります。これが反射角です。

ただし上記サンプルではSprite.bounce()をそのまま使うのではなく、少し工夫を加えています。

// ボールが左パドルに当たったら
if (ballSp.bounce(leftPaddleSp)) {
    // ボールの芯とパドルの芯のずれ。
    const swing = (ballSp.position.y - leftPaddleSp.position.y) / 3;
    // 左パドルの場合、角度は時計回りに大きくなるので、角度を大きくするにはswingを足す
    ballSp.setSpeed(MAX_SPEED, ballSp.getDirection() + swing);
    print(ballSp.getDirection())
}

// ボールが右パドルに当たったら
if (ballSp.bounce(rightPaddleSp)) {
    const swing = (ballSp.position.y - rightPaddleSp.position.y) / 3;
    // 右パドルの場合、角度は反時計回りに大きくなるので、角度を大きくするにはswingを引く
    ballSp.setSpeed(MAX_SPEED, ballSp.getDirection() - swing);
}

変数swingに代入されるのは、ボールの芯とパドルの芯のずれを表す数値です。簡単に言うと、パドルの端で打った場合には、ボールの跳ね返る角度が大きくなり、変な方向にボールが飛び出す、ということです。この工夫によって、パドルがいつも同じ角度でボールを返さなくなるので、プレイヤーはできるだけパドルのセンターでボールを受けようと、ゲームに集中するようになります。

コメントを残す

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

CAPTCHA