人工知能に関する断創録

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

壁との衝突判定

壁や積まれたブロックと重ならないようにします。

tetris04.jar

衝突判定は移動するときに行います。というわけでBlockクラスのmove()を見てみます。

    /**
     * dirの方向にブロックを移動
     * 
     * @param dir 方向
     */
    public void move(int dir) {
        switch (dir) {
            case LEFT :
                Point newPos = new Point(pos.x - 1, pos.y);
                if (field.isMovable(newPos, block)) {
                    // 衝突しなければ位置を更新
                    pos = newPos;
                }
                break;
            case RIGHT :
                newPos = new Point(pos.x + 1, pos.y);
                if (field.isMovable(newPos, block)) {
                    pos = newPos;
                }
                break;
            case DOWN :
                newPos = new Point(pos.x, pos.y + 1);
                if (field.isMovable(newPos, block)) {
                    pos = newPos;
                }
                break;
        }
    }

移動先の座標(newPos)を求めた後、FieldクラスのisMovable()を使って移動先で壁やつまれたブロックと衝突しないか調べ、移動できる(衝突しない)場合のみ移動させます。

Blockクラスにフィールドの参照(field)を渡していたのはここで使うためです。ブロックとの衝突を判定するためにはフィールドの情報を知る必要があるためです。

ちなみに回転の場合も同じ方法でできます。

    /**
     * ブロックを回転される
     */
    public void turn() {
        int[][] turnedBlock = new int[ROW][COL];

        // 回転したブロック
        for (int i = 0; i < ROW; i++) {
            for (int j = 0; j < COL; j++) {
                turnedBlock[j][ROW - 1 - i] = block[i][j];
            }
        }

        // 回転可能か調べる
        if (field.isMovable(pos, turnedBlock)) {
            block = turnedBlock;
        }
    }

次にFieldクラスのisMovable()を見てみます。

    /**
     * ブロックを移動できるか調べる
     * @param newPos ブロックの移動先座標
     * @param block ブロック
     * @return 移動できたらtrue
     */
    public boolean isMovable(Point newPos, int[][] block) {
        // block=1のマスすべてについて衝突しているか調べる
        // どれか1マスでも衝突してたら移動できない
        for (int i=0; i<Block.ROW; i++) {
            for (int j=0; j<Block.COL; j++) {
                if (block[i][j] == 1) {  // 4x4内でブロックのあるマスのみ調べる
                    if (newPos.y + i < 0) {  // そのマスが画面の上端外のとき
                        // ブロックのあるマスが壁のある0列目以下または
                        // COL-1列目以上に移動しようとしている場合は移動できない
                        if (newPos.x + j <= 0 || newPos.x+j >= COL-1) {
                            return false;
                        }
                    } else if (field[newPos.y+i][newPos.x+j] == 1) {
                        // フィールド内で
                        // 移動先にすでにブロック(壁含む)がある場合は移動できない
                        return false;
                    }
                }
            }
        }
        
        return true;
    }

4×4マスの中でブロックのあるマスそれぞれに対し、フィールド上にブロックがあるか調べています。1つでもある場合は移動できないためfalseを返します。