實現 iOS 上的井字游戲

jopen 10年前發布 | 12K 次閱讀 IOS iOS開發 移動開發

實現 iOS 上的井字游戲

實現 iOS 上的井字游戲

簡介

本文介紹如何用 MVC 模式在 iOS 上實現雙人對戰的井字游戲. 讀者最好有一些 iOS 編程基礎, 以便更好的理解本文的代碼. 希望這篇文章對提高讀者的 iOS 和 MVC 編程水平有所幫助.

背景

井字游戲

關于游戲的規則我就不多說了, 相信大家都知道怎么玩. (如果不清楚游戲規則, 請點 這里). 下面要介紹的是人和人對戰的井字游戲, 至于人機對戰不屬于本文討論的范圍.

MVC 模式

MVC 是 iOS 開發中常用的一種設計模式. MVC 把應用程序中的對象分成三類:

  • Model: 只負責程序中的數據部分, 與用戶界面無關.

  • View: 負責程序界面的顯示和用戶交互部分.

  • Controller: 是連接 Model 和 View 的一條紐帶. 比如, 它把用戶輸入的數據傳給 Model, 或者把 Model 的數據傳給 View. 

我們的游戲將使用 MVC 模式來實現. 下面的圖片是 MVC 各部分之間的關系:

 

實現 iOS 上的井字游戲

MVC 的更多內容請點 這里.

實現

Model

我們已經講過, Model 對象與用戶界面無關.  游戲項目中, 有個類 (TTTicTacToe.m), 跟用戶界面沒有半毛錢關系, 純粹是用來實現游戲邏輯, 保存游戲狀態的. 比如:  棋盤 - 一個簡單的 char 二維數組, 保存玩家每一步走法的函數, 判斷有沒有玩家勝出的函數等等. 而 View 則通過 UIButton 把游戲的狀態顯示出來.

數組跟按鈕之間的映射

我們已經講過, 游戲的狀態保存在 Model 類的一個二維數組中. 而棋盤則用 UIButton 對象實現. 當 View 要在用戶界面顯示游戲狀態的時候, 需要找個方法, 把二維數組跟 UIButton 對象關聯起來. 由于 UIButton 對象通過 tag (也就是 ID) 訪問, 我們從 1 到 16, 給它編個號. 然后再想辦法跟數組關聯起來就可以了.  Model 的二維數組看起來像醬紫:

實現 iOS 上的井字游戲

通過這個公式: 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

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!