人工知能に関する断創録

このブログでは人工知能のさまざまな分野について調査したことをまとめています(更新停止: 2019年12月31日)

反射方向の調整

ブロックを壊す(2007/7/15)を何度かプレイしてみるとわかりますが毎回同じパターンが再現されます。これはラケットの反射方向が毎回同じだからです。これだとプレイヤーがボールの動きをまったく制御できないのでゲーム性がないです。そんなわけでボールがラケットに当たる位置に応じてボールの反射方向が変わるようにしてみます。

breakout05.jar

まずラケットに当たる位置を定義します。

    // ボールの当たり位置
    public static final int NO_COLLISION = 0;  // 未衝突
    public static final int LEFT = 1;
    public static final int RIGHT = 2;

NO_COLLISIONはラケットにボールが当たらなかったとき、LEFTはラケットの左半分にボールが当たったとき、RIGHTはラケットの右半分にボールが当たったときを表しています。ラケットの左半分に当たったときと右半分に当たったときで反射方向を変えます。

前回までのcollideWith()は、ボールが当たったらtrue、当たらなかったらfalseを返していましたが、ボールが当たった位置を返すように変更します。

    /**
     * ボールが当たった位置を返す
     * 
     * @param ball ボール
     * @return ボールに当たったらtrue
     */
    public int collideWith(Ball ball) {
        // ラケットの矩形
        Rectangle racketRectLeft = new Rectangle(
                centerPos - WIDTH / 2, MainPanel.HEIGHT - HEIGHT,
                WIDTH / 2, HEIGHT);
        Rectangle racketRectRight = new Rectangle(
                centerPos, MainPanel.HEIGHT - HEIGHT,
                WIDTH / 2, HEIGHT);
        // ボールの矩形
        Rectangle ballRect = new Rectangle(
                ball.getX(), ball.getY(),
                ball.getSize(), ball.getSize());

        // ラケットとボールの矩形領域が重なったら当たっている
        if (racketRectLeft.intersects(ballRect)) {
            return LEFT;
        } else if (racketRectRight.intersects(ballRect)) {
            return RIGHT;
        }

        return NO_COLLISION;
    }

ラケットを半分に分割し、左側の矩形と右側の矩形のRectangleを求めています。ボールが左右のどちらのRectangleに当たっているか調べてLEFTかRIGHTを返しています。

MainPanelのrun()内でボールが当たった位置に応じて反射方向を変えています。

    /**
     * ゲームループ
     * 
     */
    public void run() {
        while (true) {
            // ボールの移動
            ball.move();

            // ラケットとボールの衝突処理
            int collidePos = racket.collideWith(ball);
            // ラケットに当たっていたら
            if (collidePos != Racket.NO_COLLISION) {
                // ボールの当たった位置に応じてボールの速度を変える
                switch (collidePos) {
                    case Racket.LEFT:
                        // ラケットの左側に当たったときは左に反射するようにしたい
                        // もしボールが右に進んでいたら反転して左へ
                        // 左に進んでいたらそのまま
                        if (ball.getVX() > 0) ball.boundX();
                        ball.boundY();
                        break;
                    case Racket.RIGHT:
                        // ラケットの右側に当たったときは右に反射するようにしたい
                        // もしボールが左に進んでいたら反転して右へ
                        // 右に進んでいたらそのまま
                        if (ball.getVX() < 0) ball.boundX();
                        ball.boundY();
                        break;
                }
            }

            ・・・
        }
    }

コメントのとおりです。もしラケットの左側に当たったら左に反射するようにし、ラケットの右側に当たったら右に反射するようにしました。これでボールが反射する方向をある程度制御できます。