読者です 読者をやめる 読者になる 読者になる

人工知能に関する断創録

人工知能、認知科学、心理学、ロボティクス、生物学などに興味を持っています。このブログでは人工知能のさまざまな分野について調査したことをまとめています。最近は、機械学習、Deep Learning、Kerasに関する記事が多いです。



ブロックの移動と回転

キー操作でブロックが移動、回転するようにします。スペースキーで回転。NキーでI型ブロックへ変更です。

tetris03.jar

キー操作

まずはキー操作から見てみます。矢印キーでブロックが移動し、スペースキーか上キーで回転するようにします。そのためにはMainPanelにKeyListenerとキー関連メソッドを追加すればいいですね。キーボードの使い方(2005/1/15)を参照してください。

    public void keyTyped(KeyEvent e) {
    }

    public void keyPressed(KeyEvent e) {
        int key = e.getKeyCode();

        if (key == KeyEvent.VK_LEFT) { // ブロックを左へ移動
            block.move(Block.LEFT);
        } else if (key == KeyEvent.VK_RIGHT) { // ブロックを右へ移動
            block.move(Block.RIGHT);
        } else if (key == KeyEvent.VK_DOWN) { // ブロックを下へ移動
            block.move(Block.DOWN);
        } else if (key == KeyEvent.VK_SPACE ||
                   key == KeyEvent.VK_UP) { // ブロックを回転
            block.turn();
        } else if (key == KeyEvent.VK_N) {  // バーブロックを表示
            block.createBarBlock();
        }

        repaint();
    }

    public void keyReleased(KeyEvent e) {
    }

各方向キー(VK_LEFTなど)を押したときはブロックが移動(move)、スペースキー(VK_SPACE)か上キー(VK_UP)でブロックが回転(turn)するようにしてます。Nキー(VK_N)を押したときにcreateBarBlock()を呼び出してますがこれはテスト用です。

移動処理

次にブロックの移動処理です。Blockクラスのmove()です。先ほどのmove()をよく見ると引数があります。次の3つです。move()にこれらの引数を渡して移動する方向を決めています。

    // 移動方向
    public static final int LEFT = 0;
    public static final int RIGHT = 1;
    public static final int DOWN = 2;

ではmove()です。

    /**
     * dirの方向にブロックを移動
     * 
     * @param dir 方向
     */
    public void move(int dir) {
        switch (dir) {
            case LEFT :
                Point newPos = new Point(pos.x - 1, pos.y);
                pos = newPos;
                break;
            case RIGHT :
                newPos = new Point(pos.x + 1, pos.y);
                pos = newPos;
                break;
            case DOWN :
                newPos = new Point(pos.x, pos.y + 1);
                pos = newPos;
                break;
        }
    }

移動方向(dir)ごとに処理を分岐しています。newPosは移動先です。わざわざnewPosを使う必要ないと思われるかもしれませんが、後でブロックに衝突してないか確かめる処理を間に追加するため分けています。

回転処理

次に回転処理です。これはいくつかやり方があります。よく見るのはブロックごとに全回転パターンをあらかじめ用意しておき、回転ボタンを押したら切り替えるという方法です。

今回はもう少し簡単な方法を取ります。

    /**
     * ブロックを回転される
     */
    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];
            }
        }

        block = turnedBlock;
    }

ミソはforループ内の式です。ブロックは4x4マスでできています。(i,j)の位置にあるブロックを(j,ROW-1-i)に移せば右回転します。ROWは4です。

かなり巧妙な方法ですが下図で確かめてください。回転の全パターン用意するより断然楽ですねー。ただ元祖テトリスの回転パターンと若干違うようですが・・・

f:id:aidiary:20090914220009g:plain

実装してませんが左回転したかったら上の逆

   turnedBlock[ROW - 1 - j][i] = block[i][j]

でできます。

さあ実行して回転してみましょう。スペースで回転できます。おーよく回ってますね!四角ブロックだと回転してるか見た目にはわからないですが(笑)

というわけで暫定的に棒型ブロックも追加してあります。Nキーで棒型ブロックにしてから回転してみてください。回転を確認できます。