网络游戏实例vc++网络五子棋Word文档下载推荐.docx
《网络游戏实例vc++网络五子棋Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《网络游戏实例vc++网络五子棋Word文档下载推荐.docx(27页珍藏版)》请在冰豆网上搜索。
它负责响应Receive
的消息。
服务器端和客户端都用这个socket发送和接受数据。
_CMessg.h/CMessg.cpp:
发送和接受的数据的定义。
它采用串行化的方式对网络数据进行处理。
五子棋规则部分包括如下文件。
_Match.h/Match.cpp:
Match类中保存着当前的棋盘,它还负责判断是否能够在指定的位置落子,
是否出现输赢局面。
1.4代码详细分析
下面将分析网络五子棋游戏中的网络控制、五子棋规则和视图控制部分的相关代码。
_网络控制部分:
CServerSocket、CClientSocket和CMessg。
第4章网络游戏开发209
CServerSocket类是一个专门用来监听客户端连接的Socket类,它继承于CSocket,响应OnAccept
消息。
CServerSocket类声明如下:
classCServerSocket:
publicCSocket
{
public:
CFiveChessView*m_view;
//主视图的指针,为接受连接函数服务
UINTm_uPort;
//需要监听的端口
BOOLInit(UINTport,CFiveChessView*dlg);
//socket的初始化
virtualvoidOnAccept(intnErrorCode);
//接受连接消息处理函数
};
在ServerSocket.cpp中的核心代码如下,其中成员函数Init负责初始化ServerSocket,而OnAccept
函数负责接收客户端连接。
BOOLCServerSocket:
:
Init(UINTport,CFiveChessView*view)
m_uPort=port;
m_view=view;
//创建socket
if(Create(m_uPort)==FALSE)
AfxMessageBox("
ServerSocketCreateError"
);
returnFALSE;
}
//监听socket
if(Listen()==FALSE)
ServerListenError"
returnTRUE;
voidCServerSocket:
OnAccept(intnErrorCode)//接受客户端连接
CSocket:
OnAccept(nErrorCode);
//调用视图类中的连接处理函数
m_view->
ProcessPendingAccept();
CClientSocket类是一个专门用做会话的类,它负责数据的发送和接收。
它继承自CSocket,负责
响应OnReceive和OnClose消息。
另外,作为CSocket类的继承类,理所当然的采用了串行化的方式
来处理网络数据。
网络数据是由CMessg的对象构成的。
另外,在CClientSocket类中还定义了几个静态函数,它们用来得到本机的名字和本机的IP地址。
CClientSocket类声明如下:
classCClientSocket:
210VisualC++游戏开发技术与实例
CArchive*m_aSessionIn;
//输入数据的串行化
CArchive*m_aSessionOut;
//输出数据的串行化
CSocketFile*m_sfSocketFile;
//Socket关联文件指针
//视图指针
boolm_bInit;
//是否初始化
boolm_bClose;
//连接是否已关闭
voidInit(CFiveChessView*view);
//socket和串行化相关的初始化
BOOLSendMessage(CMessg*msg);
//发送消息的函数
voidCloseSocket();
//关闭socket函数
//几个静态函数,用来得到主机名和主机IP地址
staticintGetLocalHostName(CString&
sHostName);
//获得本地计算机名称
staticintGetIpAddress(constCString&
sHostName,CString&
sIpAddress);
//获得本地IP
sHostName,BYTE&
f0,BYTE&
f1,BYTE&
f2,BYTE
&
f3);
//这个静态函数根据GetLastError()返回的tag找到网络失败的原因
staticCStringErrorReason(inttag);
virtualvoidOnReceive(intnErrorCode);
//数据接受消息的处理函数
virtualvoidOnClose(intnErrorCode);
//socket关闭的消息处理函数
ClientSocket.cpp中的核心代码如下(构造函数负责部分初始化工作):
CClientSocket:
CClientSocket()
m_aSessionIn=NULL;
m_aSessionOut=NULL;
m_sfSocketFile=NULL;
m_bInit=false;
m_bClose=false;
析构函数负责清除内存。
~CClientSocket()
if(m_aSessionIn)
deletem_aSessionIn;
if(m_aSessionOut)
deletem_aSessionOut;
if(m_sfSocketFile)
deletem_sfSocketFile;
OnReceive函数负责接收对方发送过来的数据,并对数据进行相应的处理。
这是一个消息响应
函数:
voidCClientSocket:
OnReceive(intnErrorCode)
OnReceive(nErrorCode);
do
第4章网络游戏开发211
CMessgtemp;
temp.Serialize(*m_aSessionIn);
m_sMsgList+=temp.m_strText;
//加入新的对话内容
//把新的对话内容显示在主视图窗口的一个Edit控件中
m_outputedit.SetWindowText(m_view->
m_sMsgList);
//把Edit窗口中显示的内容滚动到当前的位置
m_iLineCurrentPos=m_view->
m_outputedit.GetLineCount();
m_outputedit.LineScroll(m_view->
m_iLineCurrentPos);
//判断对方发送过来的数据是否是落子的位置
if(m_view->
m_match.CanDown(temp.m_x,temp.m_y,m_view->
m_who%2+1))
//是对方发送的落子信息
m_turn=temp.m_turn;
//该轮到我走棋了
Invalidate(FALSE);
//刷新视图,显示对方的走子位置
//对方是否赢了
m_match.IsWin(m_view->
m_who%2+1,m_view->
m_winpos))
m_bWin=TRUE;
//对方赢了
m_bOver=TRUE;
你输了"
//显示输棋的对话框
m_sMsgList+="
;
while(!
m_aSessionIn->
IsBufferEmpty());
Init函数负责初始化串行化socket:
Init(CFiveChessView*view)
m_sfSocketFile=newCSocketFile(this);
m_aSessionIn=newCArchive(m_sfSocketFile,CArchive:
load);
m_aSessionOut=newCArchive(m_sfSocketFile,CArchive:
store);
this->
SendMessage函数负责串行化数据到对方socket:
BOOLCClientSocket:
SendMessage(CMessg*msg)
if(m_aSessionOut!
=NULL)
msg->
Serialize(*m_aSessionOut);
//输出串行化
m_aSessionOut->
Flush();
//直接发送
212VisualC++游戏开发技术与实例
else
//对方关闭了连接
m_bClose=true;
CloseSocket();
关闭Socket、清除串行化数据的工作由函数CloseSocket完成:
CloseSocket()
Close();
对方关闭了Socket的消息响应处理函数OnClose:
OnClose(intnErrorCode)
OnClose(nErrorCode);
GetLocalHostName函数负责获得本地计算机名称:
intCClientSocket:
GetLocalHostName(CString&
sHostName)
charszHostName[256];
intnRetCode;
nRetCode=gethostname(szHostName,sizeof(szHostName));
if(nRetCode!
=0)
//产生错误
sHostName=_T("
没有取得"
returnGetLastError();
第4章网络游戏开发213
sHostName=szHostName;
return0;
GetIpAddress函数负责获得本地IP地址:
GetIpAddress(constCString&
sIpAddress)
structhostentFAR*lpHostEnt=gethostbyname(sHostName);
if(lpHostEnt==NULL)
sIpAddress=_T("
"
//获取IP
LPSTRlpAddr=lpHostEnt->
h_addr_list[0];
if(lpAddr)
structin_addrinAddr;
memmove(&
inAddr,lpAddr,4);
//转换为标准格式
sIpAddress=inet_ntoa(inAddr);
if(sIpAddress.IsEmpty())
GetIpAddress的一个重载:
f1,BYTE
f2,BYTE&
f3)
f0=f1=f2=f3=0;
f0=inAddr.S_un.S_un_b.s_b1;
f1=inAddr.S_un.S_un_b.s_b2;
f2=inAddr.S_un.S_un_b.s_b3;
f3=inAddr.S_un.S_un_b.s_b4;
214VisualC++游戏开发技术与实例
CMessg类是一个数据类,它继承于CObject。
在这个程序中,让CMessg类发挥串行化数据的作
用。
CMessg类中包括了几个主要的成员变量:
CStringm_strText;
intm_turn;
intm_x;
intm_y;
其中m_strText表示聊天的字符串;
m_turn表示轮到谁走棋;
m_x表示落子的水平方向的位置;
m_y表示落子的竖直方向的位置。
这4个数据构成了网络传输数据的全部信息。
事实上,在发送具体的CMessg数据的时候并不需要用到所有这4个成员变量。
例如,用户只是
聊天的时候,只需要填充m_strText就可以了,m_turn、m_x和m_y会被初始填充为–1,表示没有子
落下。
而当用户落子的时候,m_strText会被初始填充成NULL,m_turn、m_x和m_y会被填充成具体
的落子位置和轮换信息。
CMessg.h中的核心代码如下:
classCMessg:
publicCObject
protected:
DECLARE_DYNCREATE(CMessg)
//聊天的内容
//轮到谁落子
//落子的水平位置
//落子的竖直位置
voidInit();
//初始化
virtualvoidSerialize(CArchive&
ar);
//串行化数据类
CMessg.cpp中的核心代码如下:
IMPLEMENT_DYNCREATE(CMessg,CObject)
voidCMessg:
Init()//初始化
m_strText=_T("
m_x=-1;
m_y=-1;
m_turn=-1;
Serialize(CArchive&
ar)//数据串行化
if(ar.IsStoring())
ar<
<
m_strText;
m_turn;
m_x;
m_y;
第4章网络游戏开发215
ar>
>
_Match类(五子棋规则)
正如前面所说的,每一种游戏都有一定的规则,Match类正是五子棋的规则处理类。
在Match类中保存着一个当前的棋盘,它是一个二维的数组intchessboard[LW][LW]。
如果
chessboard[x][y]为0,则表示(x,y)的位置上没有棋子;
如果chessboard[x][y]为1表示该位置上有黑子;
如果chessboard[x][y]为2,则表示该位置上有白子。
Match类还负责判断是否能在某个位置落子,是否有人赢棋。
Cmatch类声明如下:
#defineLW19//棋盘的水平竖直方向的格数
classMatch
Match();
virtual~Match();
intchessboard[LW][LW];
//0表示没有子落下;
1表示黑子落下;
2表示白子落下
BOOLCanDown(intx,inty,intwho);
//是否能在x,y的位置落子
BOOLIsWin(intwho,intpos[5][2]);
//判断是否赢棋
voidClear();
//清除棋盘内容
Match.cpp中的核心代码如下(在构造函数里初始化棋盘):
Match:
Match()
for(inti=0;
i<
LW;
i++)
for(intj=0;
j<
j++)
chessboard[i][j]=0;
Clear函数负责清除棋盘内容:
voidMatch:
Clear()
CanDown函数负责判断在点(x,y)位置是否能落子:
216VisualC++游戏开发技术与实例
BOOLMatch:
CanDown(intx,inty,intwho)
if(x<
0||x>
=LW||y<
0||y>
=LW)
if(chessboard[x][y]!
chessboard[x][y]=who;
判断玩家是否赢棋,如果赢棋则标注五子连珠的位置。
IsWin(intwho,intpos[5][2])
inti,j;
for(i=0;
for(j=0;
if(chessboard[i][j]==who)
//水平方向
if(j+4<
LW)
if(chessboard[i][j+1]==who&
chessboard[i][j+2]==who&
chessboard[i][j+3]==who&
chess
board[i][j+4]==who)
{//赢棋
//标注赢棋的关键子的位置
for(intk=0;
k<
5;
k++)
pos[k][0]=i;
pos[k][1]=j+k;
//垂直
if(i+4<
if(chessboard[i+1][j]==who&
chessboard[i+2][j]==who&
chessboard[i+3][j]==who&
board[i+4][j]==who)
pos[k][0]=i+k;
pos[k][1]=j;
LW&
j+4<
LW)//东南向
第4章网络游戏开发217
if(chessboard[i+1][j+1]==who&
chessboard[i+2][j+2]==who&
chessboard[i+3][j+3]==who&
chessboard[i+4][j+4]==who)
k++)//标注赢棋的关键子的位置
//东北
if(i-4>
0&
if(chessboard[i-1][j+1]==who&
chessboard[i-2][j+2]==who&
chessboard[i-