本文實例為大家分享了java實現俄羅斯方塊的具體代碼,供大家參考,具體內容如下
使用一個二維數組保存遊戲的地圖:
// 遊戲地圖格子,每個格子保存一個方塊,數組紀錄方塊的狀態private State map[][] = new State[rows][columns];
遊戲前先將所有地圖中的格子初始化為空:
/* 初始化所有的方塊為空*/for (int i = 0; i < map.length; i++) { for (int j = 0; j < map[i].length; j++) { map[i][j] = State.EMPTY; }}玩遊戲過程中,我們能夠看到界面上的方塊,那麼就得將地圖中所有的方塊繪製出來,當然,除了需要繪製方塊外,遊戲積分和遊戲結束的字符串在必要的時候也需要繪製:
/** * 繪製窗體內容,包括遊戲方塊,遊戲積分或結束字符串*/@Overridepublic void paint(Graphics g) { super.paint(g); for (int i = 0; i < rows; i++) { for (int j = 0; j < columns; j++) { if (map[i][j] == State.ACTIVE) { // 繪製活動塊g.setColor(activeColor); g.fillRoundRect(j * BLOCK_SIZE, i * BLOCK_SIZE + 25, BLOCK_SIZE - 1, BLOCK_SIZE - 1, BLOCK_SIZE / 5, BLOCK_SIZE / 5); } else if (map[i][j] == State.STOPED) { // 繪製靜止塊g.setColor(stopedColor); g.fillRoundRect(j * BLOCK_SIZE, i * BLOCK_SIZE + 25, BLOCK_SIZE - 1, BLOCK_SIZE - 1, BLOCK_SIZE / 5, BLOCK_SIZE / 5); } } } /* 打印得分*/ g.setColor(scoreColor); g.setFont(new Font("Times New Roman", Font.BOLD, 30)); g.drawString("SCORE : " + totalScore, 5, 70); // 遊戲結束,打印結束字符串if (!isGoingOn) { g.setColor(Color.RED); g.setFont(new Font("Times New Roman", Font.BOLD, 40)); g.drawString("GAME OVER !", this.getWidth() / 2 - 140, this.getHeight() / 2); }}通過隨機數的方式產生方塊所組成的幾種圖形,一般七種圖形:條形、田形、正7形、反7形、T形、Z形和反Z形,如生成條形:
map[0][randPos] = map[0][randPos - 1] = map[0][randPos + 1] = map[0][randPos + 2] = State.ACTIVE;
生成圖形後,實現下落的操作。如果遇到阻礙,則不能再繼續下落:
isFall = true; // 是否能夠下落// 從當前行檢查,如果遇到阻礙,則停止下落for (int i = 0; i < blockRows; i++) { for (int j = 0; j < columns; j++) { // 遍歷到行中塊為活動塊,而下一行塊為靜止塊,則遇到阻礙if (map[rowIndex - i][j] == State.ACTIVE && map[rowIndex - i + 1][j] == State.STOPED) { isFall = false; // 停止下落break; } } if (!isFall) break;}如果未遇到阻礙,則下落的時候,方塊圖形整體向下移動一行:
// 圖形下落一行for (int i = 0; i < blockRows; i++) { for (int j = 0; j < columns; j++) { if (map[rowIndex - i][j] == State.ACTIVE) { // 活動塊向下移動一行map[rowIndex - i][j] = State.EMPTY; // 原活動塊變成空塊map[rowIndex - i + 1][j] = State.ACTIVE; // 下一行塊變成活動塊} }}向左、向右方向移動時是類似的操作:
/** * 向左走*/private void left() { // 標記左邊是否有阻礙boolean hasBlock = false; /* 判斷是否左邊有阻礙*/ for (int i = 0; i < blockRows; i++) { if (map[rowIndex - i][0] == State.ACTIVE) { // 判斷左邊是否為牆hasBlock = true; break; // 有阻礙,不用再循環判斷行} else { for (int j = 1; j < columns; j++) { // 判斷左邊是否有其它塊if (map[rowIndex - i][j] == State.ACTIVE && map[rowIndex - i][j - 1] == State.STOPED) { hasBlock = true; break; // 有阻礙,不用再循環判斷列} } if (hasBlock) break; // 有阻礙,不用再循環判斷行} } /* 左邊沒有阻礙,則將圖形向左移動一個塊的距離*/ if (!hasBlock) { for (int i = 0; i < blockRows; i++) { for (int j = 1; j < columns; j++) { if (map[rowIndex - i][j] == State.ACTIVE) { map[rowIndex - i][j] = State.EMPTY; map[rowIndex - i][j - 1] = State.ACTIVE; } } } // 重繪repaint(); }}向下加速移動時,就是減小每次正常狀態下落的時間間隔:
/** * 向下直走*/private void down() { // 標記可以加速下落immediate = true;}如何變換圖形方向,這裡僅使用了非常簡單的方法來實現方向變換,當然可以有更優的算法實現方向變換操作,大家可以自己研究:
/** * 旋轉方塊圖形*/private void rotate() { try { if (shape == 4) { // 方形,旋轉前後是同一個形狀return; } else if (shape == 0) { // 條狀// 臨時數組,放置旋轉後圖形State[][] tmp = new State[4][4]; int startColumn = 0; // 找到圖形開始的第一個方塊位置for (int i = 0; i < columns; i++) { if (map[rowIndex][i] == State.ACTIVE) { startColumn = i; break; } } // 查找旋轉之後是否有阻礙,如果有阻礙,則不旋轉for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { if (map[rowIndex - 3 + i][j + startColumn] == State.STOPED) { return; } } } if (map[rowIndex][startColumn + 1] == State.ACTIVE) { // 橫向條形,變換為豎立條形for (int i = 0; i < 4; i++) { tmp[i][0] = State.ACTIVE; for (int j = 1; j < 4; j++) { tmp[i][j] = State.EMPTY; } } blockRows = 4; } else { // 豎立條形,變換為橫向條形for (int j = 0; j < 4; j++) { tmp[3][j] = State.ACTIVE; for (int i = 0; i < 3; i++) { tmp[i][j] = State.EMPTY; } } blockRows = 1; } // 將原地圖中圖形修改為變換後圖形for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { map[rowIndex - 3 + i][startColumn + j] = tmp[i][j]; } } } else { // 臨時數組,放置旋轉後圖形State[][] tmp = new State[3][3]; int startColumn = columns; // 找到圖形開始的第一個方塊位置for (int j = 0; j < 3; j++) { for (int i = 0; i < columns; i++) { if (map[rowIndex - j][i] == State.ACTIVE) { startColumn = i < startColumn ? i : startColumn; } } } // 判斷變換後是否會遇到阻礙for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (map[rowIndex - 2 + j][startColumn + 2 - i] == State.STOPED) return; } } // 變換for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { tmp[2 - j][i] = map[rowIndex - 2 + i][startColumn + j]; } } // 將原地圖中圖形修改為變換後圖形for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { map[rowIndex - 2 + i][startColumn + j] = tmp[i][j]; } } // 重繪repaint(); // 重新修改行指針for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (map[rowIndex - i][startColumn + j] != null || map[rowIndex - i][startColumn + j] != State.EMPTY) { rowIndex = rowIndex - i; blockRows = 3; return; } } } } } catch (Exception e) { // 遇到數組下標越界,說明不能變換圖形形狀,不作任何處理}}當圖形下落遇到阻礙時停止,我們就需要判斷這時是否有某一行或幾行可以消除掉,這時可以先獲取每行中方塊的個數,然後再進行判斷:
int[] blocksCount = new int[rows]; // 記錄每行有方塊的列數int eliminateRows = 0; // 消除的行數/* 計算每行方塊數量*/for (int i = 0; i < rows; i++) { blocksCount[i] = 0; for (int j = 0; j < columns; j++) { if (map[i][j] == State.STOPED) blocksCount[i]++; }}如果有滿行的方塊,則消除掉該行方塊:
/* 實現有滿行的方塊消除操作*/for (int i = 0; i < rows; i++) { if (blocksCount[i] == columns) { // 清除一行for (int m = i; m >= 0; m--) { for (int n = 0; n < columns; n++) { map[m][n] = (m == 0) ? State.EMPTY : map[m - 1][n]; } } eliminateRows++; // 記錄消除行數}}最後我們再重繪顯示積分就可以了。
重複以上的生成圖形、圖形下落、左右下移動、判斷消除行的操作,一個簡單的俄羅斯方塊就完成了。
運行效果:
完整示例代碼:俄羅斯方塊
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。