简介 本文介绍如何用 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 函数判断有没有玩家获胜.
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;
int buttonID = 4 * y + x + 1;
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" );
}
for ( int i=1; i<=16; i++)
{
UIButton *b = (UIButton*)[self.view viewWithTag:i];
b.enabled = NO;
}
}
UIButton *b = (UIButton*)[self.view viewWithTag:buttonID];
b.enabled = NO;
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++)
{
UIButton*b = (UIButton*) [self.view viewWithTag:(i*4+j+1)];
UIImage *btnImage;
if ([self.game objectAtX:j andY:i] == 'X')
{
btnImage = [UIImage imageNamed:@ "xIcon.png" ];
} else
{
if ([self.game objectAtX:j andY:i] == 'O')
{
btnImage = [UIImage imageNamed:@ "oIcon.png" ];
}
}
[b setImage:btnImage forState:UIControlStateNormal];
}
}
|
历史
- Version 1.00 - Initial release