设为首页收藏本站

LUPA开源社区

 找回密码
 注册
文章 帖子 博客
LUPA开源社区 首页 业界资讯 技术文摘 查看内容

实现iOS上的井字游戏

2014-11-12 10:08| 发布者: joejoe0332| 查看: 980| 评论: 0|原作者: Boobs|来自: oschina

摘要: 本文介绍如何用 MVC 模式在 iOS 上实现双人对战的井字游戏. 读者最好有一些 iOS 编程基础, 以便更好的理解本文的代码. 希望这篇文章对提高读者的 iOS 和 MVC 编程水平有所帮助. ...
简介

  本文介绍如何用 MVC 模式在 iOS 上实现双人对战的井字游戏. 读者最好有一些 iOS 编程基础, 以便更好的理解本文的代码. 希望这篇文章对提高读者的 iOS 和 MVC 编程水平有所帮助.


Sample Image - maximum width is 600 pixels


背景

井字游戏

  关于游戏的规则我就不多说了, 相信大家都知道怎么玩. (如果不清楚游戏规则, 请点 这里). 下面要介绍的是人和人对战的井字游戏, 至于人机对战不属于本文讨论的范围.


MVC 模式

MVC 是 iOS 开发中常用的一种设计模式. MVC 把应用程序中的对象分成三类:

  • Model: 只负责程序中的数据部分, 与用户界面无关.

  • View: 负责程序界面的显示和用户交互部分.

  • Controller: 是连接 Model 和 View 的一条纽带. 比如, 它把用户输入的数据传给 Model, 或者把 Model 的数据传给 View. 

我们的游戏将使用 MVC 模式来实现. 下面的图片是 MVC 各部分之间的关系:

 

mvc

MVC 的更多内容请点 这里.


实现

Model

  我们已经讲过, Model 对象与用户界面无关.  游戏项目中, 有个类 (TTTicTacToe.m), 跟用户界面没有半毛钱关系, 纯粹是用来实现游戏逻辑, 保存游戏状态的. 比如:  棋盘 - 一个简单的 char 二维数组, 保存玩家每一步走法的函数, 判断有没有玩家胜出的函数等等. 而 View 则通过 UIButton 把游戏的状态显示出来.


数组跟按钮之间的映射

  我们已经讲过, 游戏的状态保存在 Model 类的一个二维数组中. 而棋盘则用 UIButton 对象实现. 当 View 要在用户界面显示游戏状态的时候, 需要找个方法, 把二维数组跟 UIButton 对象关联起来. 由于 UIButton 对象通过 tag (也就是 ID) 访问, 我们从 1 到 16, 给它编个号. 然后再想办法跟数组关联起来就可以了.  Model 的二维数组看起来像酱紫:

mat

  通过这个公式: 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 函数判断有没有玩家获胜.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
-(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 . 


  最后就剩下这个用按钮显示棋盘的函数了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
-(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] == &apos;X&apos;)
            {
                 // 设为 X 图标
                 btnImage = [UIImage imageNamed:@"xIcon.png"];
            }else
            {
                if([self.game objectAtX:j andY:i] == &apos;O&apos;)
                {
                    // 设为 O 图标
                    btnImage = [UIImage imageNamed:@"oIcon.png"];
                }
            }
         
            // 在按钮上面显示图标
            // 如果 btnImage 为 nil, 则不用显示
            [b setImage:btnImage forState:UIControlStateNormal];
        
}


历史

  • Version 1.00 - Initial release

酷毙

雷人

鲜花

鸡蛋

漂亮
  • 快毕业了,没工作经验,
    找份工作好难啊?
    赶紧去人才芯片公司磨练吧!!

最新评论

关于LUPA|人才芯片工程|人才招聘|LUPA认证|LUPA教育|LUPA开源社区 ( 浙B2-20090187 浙公网安备 33010602006705号   

返回顶部