e。CGame是一个抽象类,经由它派生出一人游戏类COneGame和网络游戏类CTwoGame,如图2所示。
图1 软件架构
图2 CGame类派生关系
这样,CTable类就可以通过一个CGame类的指针,在游戏初始化的时候根据具体游戏模式的要求实例化COneGame或CTwoGame类的对象;然后利用多态性,使用CGame类提供的公有接口就可以完成不同游戏模式下的不同功能了。
三、棋盘类--Ctable
(一)主要成员变量说明
* 网络连接标志--m_bConnected
用来表示当前网络连接的情况,在网络对弈游戏模式下客户端连接服务器的时候用来判断是否连接成功;事实上,它也是区分当前游戏模式的唯一标志。
* 棋盘等待标志--m_bWait与m_bOldWait
由于在玩家落子后需要等待对方落子,m_bWait标志就用来标识棋盘的等待状态。当m_bWait为TRUE时,是不允许玩家落子的。
在网络对弈模式下,玩家之间需要互相发送诸如悔棋、和棋这一类的请求消息,在发送请求后等待对方回应时,也是不允许落子的,所以需要将m_bWait标志置为TRUE。在收到对方回应后,需要恢复原有的棋盘等待状态,所以需要另外一个变量在发送请求之前保存棋盘的等待状态做恢复之用,也就是m_bOldWait。
等待标志的设置,由成员函数SetWait和RestoreWait完成。
* 网络套接字--m_sock和m_conn
在网络对弈游戏模式下,需要用到这两个套接字对象。其中m_sock对象用于做服务器时的监听之用,m_conn用于网络连接的传输。
* 棋盘数据--m_data
这是一个15*15的二位数组,用来保存当前棋盘的落子数据。其中对于每个成员来说,0表示落黑子,1表示落白子,-1表示无子。
* 游戏模式指针--m_pGame
这个CGame类的对象指针是CTable类的核心内容。它所指向的对象实体决定了CTable在执行一件事情时候的不同行为,具体的内容请参见"游戏模式"一节。
(二)主要成员函数说明
1.套接字的回调处理--Accept、Connect、Receive
本程序的套接字派生自MFC的CAsyncSocket类[6],CTable的这三个成员函数就分别提供了对套接字[7]回调事件OnAccept、OnConnect、OnReceive的实际处理,其中尤以Receive成员函数重要,它之中包含了对所有网络消息(参见"消息机制"一节)的分发处理。
2.清空棋盘--Clear
在每一局游戏开始的时候都需要调用这个函数将棋盘清空,也就是棋盘的初始化工作。在这个函数中,主要发生了这么几件事情:
* 将m_data中每一个落子位都置为无子状态(-1)。
* 按照传入的参数设置棋盘等待标志m_bWait,以供先、后手的不同情况之用
* 使用delete将m_pGame指针所指向的原有游戏模式对象从堆上删除。
3.绘制棋子--Draw
这是非常重要的一个函数,它根据参数给定的坐标和颜色绘制棋子。绘制的详细过程如下:
* 将给定的棋盘坐标换算为绘图的像素坐标。
* 根据坐标绘制棋子位图。
* 如果先前曾下过棋子,则利用R2_NOTXORPEN将上一个绘制棋子上的最后落子指示矩形擦除。
* 在刚绘制完成的棋子四周绘制最后落子指示矩形。
4.左键消息--OnLButtonUp
作为棋盘唯一响应的左键消息,它需要相应的工作如下:
* 如果棋盘等待标志m_bWait为TRUE,则直接发出警告声音并返回,即禁止落子。
* 如果点击时的鼠标坐标在合法坐标(0, 0)~(14, 14)之外,亦禁止落子。
* 如果走的步数大于1步,方才允许悔棋。
* 进行胜利判断,如胜利则修改UI状态并增加胜利数的统计。
* 如未胜利,则向对方发送已经落子的消息。
* 落子完毕,将m_bWait标志置为TRUE,开始等待对方回应。
5.绘制棋盘--OnPaint
每当WM_PAINT消息触发时,都需要对棋盘进行重绘。OnPaint作为响应绘制消息的消息处理函数使用了双缓冲技术,减少了多次绘图可能导致的图像闪烁问题。这个函数主要完成了以下工作:
* 装载棋盘位图并进行绘制。
* 根据棋盘数据绘制棋子。
* 绘制最后落子指示矩形。
6.对方落子完毕--Over
在对方落子之后,仍然需要做一些判断工作,这些工作与OnLButtonUp中的类似。
7.设置游戏模式--SetGameMode
这个函数通过传入的游戏模式参数对m_pGame指针进行了初始化,代码如下:
void CTable::SetGameMode( int nGameMode )
{
if ( 1 == nGameMode )
m_pGame = new COneGame( this );
else
m_pGame = new CTwoGame( this );
m_pGame->Init();
}
这之后,就可以利用OO的继承和多态特点来使m_pGame指针使用相同的调用来完成不同的工作了,实际上,COneGame::Init和CTwoGame::Init都是不同的。
8.胜负的判断--Win
Win是游戏中一个极其重要的算法,用来判断当前棋盘的形势是哪一方获胜。其详细内容请参见"主要算法"一节。
四、游戏模式类--CGame
上一篇:
汽车修理管理系统的开发(vfp)
下一篇:
科研管理杂志简介