壁との衝突判定
壁や積まれたブロックと重ならないようにします。
衝突判定は移動するときに行います。というわけで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を返します。