實現 iOS 上的井字游戲
實現 iOS 上的井字游戲
簡介
本文介紹如何用 MVC 模式在 iOS 上實現雙人對戰的井字游戲. 讀者最好有一些 iOS 編程基礎, 以便更好的理解本文的代碼. 希望這篇文章對提高讀者的 iOS 和 MVC 編程水平有所幫助.
背景
井字游戲
關于游戲的規則我就不多說了, 相信大家都知道怎么玩. (如果不清楚游戲規則, 請點 這里). 下面要介紹的是人和人對戰的井字游戲, 至于人機對戰不屬于本文討論的范圍.
MVC 模式
MVC 是 iOS 開發中常用的一種設計模式. MVC 把應用程序中的對象分成三類:
-
Model: 只負責程序中的數據部分, 與用戶界面無關.
-
View: 負責程序界面的顯示和用戶交互部分.
-
Controller: 是連接 Model 和 View 的一條紐帶. 比如, 它把用戶輸入的數據傳給 Model, 或者把 Model 的數據傳給 View.
我們的游戲將使用 MVC 模式來實現. 下面的圖片是 MVC 各部分之間的關系:
MVC 的更多內容請點 這里.
實現
Model
我們已經講過, Model 對象與用戶界面無關. 游戲項目中, 有個類 (TTTicTacToe.m), 跟用戶界面沒有半毛錢關系, 純粹是用來實現游戲邏輯, 保存游戲狀態的. 比如: 棋盤 - 一個簡單的 char 二維數組, 保存玩家每一步走法的函數, 判斷有沒有玩家勝出的函數等等. 而 View 則通過 UIButton 把游戲的狀態顯示出來.
數組跟按鈕之間的映射
我們已經講過, 游戲的狀態保存在 Model 類的一個二維數組中. 而棋盤則用 UIButton 對象實現. 當 View 要在用戶界面顯示游戲狀態的時候, 需要找個方法, 把二維數組跟 UIButton 對象關聯起來. 由于 UIButton 對象通過 tag (也就是 ID) 訪問, 我們從 1 到 16, 給它編個號. 然后再想辦法跟數組關聯起來就可以了. Model 的二維數組看起來像醬紫:
通過這個公式: buttonID = i*4 + j + 1, 就能把數組元素[i,j] 跟 UIButton 對象的 ID 關聯起來. 比如: 數組元素[2,3]對應的是 ID(也叫tag) 為 12 的 UIButton 對象.
View Controller
下面, 我們講下這個實現游戲邏輯的函數(包括用戶界面). 當用戶按下某個按鈕(UIButton 對象)時, 該函數就會被調用(我們把按鈕的坐標當作參數傳給它). 代碼已經寫了詳細的注釋, 我再簡單說下. View 調用 Model 對象(self.game 是 TTTicTacToe.m 類的對象)保存玩家下棋的數據的. 然后調用 redrawTable 函數, 把 Model 中的游戲狀態顯示出來(這個函數后面再講). 最后調用 self.game checkForWin 函數判斷有沒有玩家獲勝.
-(void) userMoveX:(int)x andY:(int)y { BoardCoord pos; pos.x = x; pos.y = y; //由 x 和 y 坐標推算出按鈕的 ID. int buttonID = 4 * y + x + 1; // 玩家最多走 16 步棋. if(self.counter > 15) return; // 保存玩家下棋的狀態. [self.game updateBoardAtPos:pos withPlayer:((self.counter) % 2)]; // 更新用戶界面 [self redrawTable]; // 判斷有沒有玩家勝出? if([self.game checkForWin:pos]) { if((self.counter % 2) == 0) { NSLog(@"Win X"); self.status.text = @"Player X wins!"; } else { self.status.text = @"Player O wins!"; NSLog(@"Win O"); } // 如果其中一個玩家獲勝, 游戲結束 // 禁用所有按鈕(Disabled) for(int i=1; i<=16; i++) { //通過 tag 獲取按鈕對象 UIButton *b = (UIButton*)[self.view viewWithTag:i]; // 禁用按鈕 b.enabled = NO; } } // 玩家當前點到的按鈕也要禁用 UIButton *b = (UIButton*)[self.view viewWithTag:buttonID]; b.enabled = NO; // counter 增 1 self.counter++; }
注意: (self.counter) % 2 這行代碼中, self.counter 表示玩家總共已經下了幾步棋. 對 2 求余, 結果是 0 表示玩家 X, 1 表示玩家 O .
最后就剩下這個用按鈕顯示棋盤的函數了:
-(void) redrawTable { for(int i=0; i < SIZE; i++) for(int j=0; j < SIZE; j++) { // 獲取按鈕的 handle UIButton*b = (UIButton*) [self.view viewWithTag:(i*4+j+1)]; UIImage *btnImage; if([self.game objectAtX:j andY:i] == 'X') { // 設為 X 圖標 btnImage = [UIImage imageNamed:@"xIcon.png"]; }else { if([self.game objectAtX:j andY:i] == 'O') { // 設為 O 圖標 btnImage = [UIImage imageNamed:@"oIcon.png"]; } } // 在按鈕上面顯示圖標 // 如果 btnImage 為 nil, 則不用顯示 [b setImage:btnImage forState:UIControlStateNormal]; } }
歷史
-
Version 1.00 - Initial release