小型网络游戏实例(vc++)——网络五子棋
来源:互联网 发布:2345下载软件 编辑:程序博客网 时间:2024/04/29 20:34
转载请注明出处
本文章的源代码下载地址
前面介绍了Socket网络开发基础,下面通过一个网络五子棋的例子来介绍小型网络游戏的制作方
法和流程。
1.1 主程序结构和流程
对于一般的小型网络游戏设计来说,可以分成如下的几个模块。
_ 服务器模块:负责建立游戏服务器并接受客户端的连接和处理客户端的数据。
_ 客户端模块:负责连接到服务器并处理和服务器的会话。
_ 游戏规则模块:负责游戏的控制和结果的判断,使游戏按规则进行。
_ 视图控制模块:负责控制整个程序的操作,负责处理用户的输入和游戏的界面绘制。
本节的网络五子棋游戏就是按照以上的设计思路来安排的。
第4 章网络游戏开发207
1.2 实例演示
实例运行时的界面如图4.7 所示。实现的主要功能有:双人对下五子棋,聊天。
208 Visual C++游戏开发技术与实例
图4.7 网络五子棋的运行界面
1.3 实例设计
利用Win32 AppWizard 建立一个单文档工程,工程名称为FiveChess。工程主要包括以下的一些
文件。
其中窗体/视图/文档文件包括如下文件。
_ MainFrm.h /MainFrm.cpp:主窗体框架。
_ FiveChessView.h/FiveChessView.cpp:棋盘界面的显示,鼠标消息的处理和发送网络数据(聊
天和下棋)。
_ FiveChessDoc.h/FiveChessDoc.cpp:文档部分。
网络控制部分包括如下文件。
_ ServerSocket.h/ServerSocket.cpp:服务器端用来监听的socket,它继承自CSocket。它负责响应
客户端连接消息。
_ ClientSocket.h/ClientSocket.cpp:用来会话的socket,它也继承于CSocket。它负责响应Receive
的消息。服务器端和客户端都用这个socket 发送和接受数据。
_ CMessg.h/CMessg.cpp:发送和接受的数据的定义。它采用串行化的方式对网络数据进行处理。
五子棋规则部分包括如下文件。
_ Match.h/Match.cpp:Match类中保存着当前的棋盘,它还负责判断是否能够在指定的位置落子,
是否出现输赢局面。
1.4 代码详细分析
下面将分析网络五子棋游戏中的网络控制、五子棋规则和视图控制部分的相关代码。
_ 网络控制部分:CServerSocket、CClientSocket和CMessg。
第4 章网络游戏开发209
CServerSocket 类是一个专门用来监听客户端连接的Socket类,它继承于CSocket,响应OnAccept
消息。CServerSocket 类声明如下:
classCServerSocket : public CSocket{public:CFiveChessView* m_view; //主视图的指针,为接受连接函数服务UINTm_uPort; //需要监听的端口BOOLInit(UINT port, CFiveChessView* dlg); //socket 的初始化public:virtualvoid OnAccept(int nErrorCode); //接受连接消息处理函数};
在ServerSocket.cpp 中的核心代码如下,其中成员函数Init 负责初始化ServerSocket,而OnAccept
函数负责接收客户端连接。
BOOLCServerSocket::Init(UINT port, CFiveChessView* view){m_uPort=port;m_view=view;//创建socketif(Create(m_uPort)==FALSE){AfxMessageBox("ServerSocket Create Error");returnFALSE;}//监听socketif(Listen()==FALSE){AfxMessageBox("ServerListen Error");returnFALSE;}returnTRUE;}voidCServerSocket::OnAccept(int nErrorCode) //接受客户端连接{CSocket::OnAccept(nErrorCode);//调用视图类中的连接处理函数m_view->ProcessPendingAccept();}
CClientSocket 类是一个专门用做会话的类,它负责数据的发送和接收。它继承自CSocket,负责
响应OnReceive 和OnClose消息。另外,作为CSocket类的继承类,理所当然的采用了串行化的方式
来处理网络数据。网络数据是由CMessg 的对象构成的。
另外,在CClientSocket 类中还定义了几个静态函数,它们用来得到本机的名字和本机的IP 地址。
CClientSocket 类声明如下:
class CClientSocket : public CSocket{public:210 Visual C++游戏开发技术与实例CArchive* m_aSessionIn; //输入数据的串行化CArchive* m_aSessionOut; //输出数据的串行化CSocketFile* m_sfSocketFile; //Socket 关联文件指针CFiveChessView * m_view; //视图指针bool m_bInit; //是否初始化bool m_bClose; //连接是否已关闭public:void Init(CFiveChessView * view); //socket 和串行化相关的初始化BOOL SendMessage(CMessg * msg); //发送消息的函数void CloseSocket(); //关闭socket 函数public: //几个静态函数,用来得到主机名和主机IP 地址static int GetLocalHostName(CString&sHostName); //获得本地计算机名称static int GetIpAddress(const CString&sHostName, CString &sIpAddress);//获得本地IPstatic int GetIpAddress(const CString&sHostName, BYTE &f0,BYTE &f1,BYTE &f2,BYTE&f3);//获得本地IP//这个静态函数根据GetLastError()返回的tag 找到网络失败的原因static CString ErrorReason(int tag);public:virtual void OnReceive(int nErrorCode); //数据接受消息的处理函数virtual void OnClose(int nErrorCode); //socket 关闭的消息处理函数};
ClientSocket.cpp 中的核心代码如下(构造函数负责部分初始化工作):
CClientSocket::CClientSocket(){m_aSessionIn=NULL;m_aSessionOut=NULL;m_sfSocketFile=NULL;m_bInit=false;m_bClose=false;}
析构函数负责清除内存。
CClientSocket::~CClientSocket(){if(m_aSessionIn)delete m_aSessionIn;if(m_aSessionOut)delete m_aSessionOut;if(m_sfSocketFile)delete m_sfSocketFile;}
OnReceive 函数负责接收对方发送过来的数据,并对数据进行相应的处理。这是一个消息响应
函数:
void CClientSocket::OnReceive(int nErrorCode){CSocket::OnReceive(nErrorCode);do{CMessg temp;temp.Serialize(*m_aSessionIn); //输入数据的串行化m_view->m_sMsgList+=temp.m_strText; //加入新的对话内容//把新的对话内容显示在主视图窗口的一个Edit 控件中m_view->m_outputedit.SetWindowText(m_view->m_sMsgList);//把Edit 窗口中显示的内容滚动到当前的位置m_view->m_iLineCurrentPos=m_view->m_outputedit.GetLineCount();m_view->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_view->m_turn=temp.m_turn; //该轮到我走棋了m_view->Invalidate(FALSE); //刷新视图,显示对方的走子位置//对方是否赢了if(m_view->m_match.IsWin(m_view->m_who%2+1,m_view->m_winpos)){m_view->m_bWin=TRUE; //对方赢了m_view->m_bOver=TRUE;m_view->Invalidate(FALSE);AfxMessageBox("你输了"); //显示输棋的对话框m_view->m_sMsgList+="你输了";m_view->m_outputedit.SetWindowText(m_view->m_sMsgList);m_view->m_iLineCurrentPos=m_view->m_outputedit.GetLineCount();m_view->m_outputedit.LineScroll(m_view->m_iLineCurrentPos);}}}while (!m_aSessionIn->IsBufferEmpty());}
Init 函数负责初始化串行化socket:
void CClientSocket::Init(CFiveChessView * view){m_sfSocketFile= new CSocketFile(this);m_aSessionIn=new CArchive(m_sfSocketFile,CArchive::load);m_aSessionOut=newCArchive(m_sfSocketFile,CArchive::store);m_bClose=false;this->m_view=view;}
SendMessage 函数负责串行化数据到对方socket:
BOOL CClientSocket::SendMessage(CMessg * msg)
{
if (m_aSessionOut != NULL)
{
msg->Serialize(*m_aSessionOut); //输出串行化
m_aSessionOut->Flush(); //直接发送
return TRUE;
}
else
{
//对方关闭了连接
m_bClose=true;
CloseSocket();
return FALSE;
}
}
关闭Socket、清除串行化数据的工作由函数CloseSocket完成:
void CClientSocket::CloseSocket(){if(m_aSessionIn){delete m_aSessionIn;m_aSessionIn=NULL;}if(m_aSessionOut){delete m_aSessionOut;m_aSessionOut=NULL;}if(m_sfSocketFile){delete m_aSessionOut;m_sfSocketFile=NULL;}Close();m_bInit=false;m_bClose=true;}
对方关闭了Socket 的消息响应处理函数OnClose:
void CClientSocket::OnClose(int nErrorCode){m_bClose=true;CloseSocket();CSocket::OnClose(nErrorCode);}
GetLocalHostName 函数负责获得本地计算机名称:
int CClientSocket::GetLocalHostName(CString&sHostName){char szHostName[256];int nRetCode;nRetCode=gethostname(szHostName,sizeof(szHostName));if(nRetCode!=0){//产生错误sHostName=_T("没有取得");return GetLastError();}sHostName=szHostName;return 0;}
GetIpAddress 函数负责获得本地IP地址:
int CClientSocket::GetIpAddress(const CString&sHostName, CString &sIpAddress)
{
struct hostent FAR * lpHostEnt=gethostbyname(sHostName);
if(lpHostEnt==NULL)
{
//产生错误
sIpAddress=_T("");
return GetLastError();
}
//获取IP
LPSTR lpAddr=lpHostEnt->h_addr_list[0];
if(lpAddr)
{
struct in_addr inAddr;
memmove(&inAddr,lpAddr,4);
//转换为标准格式
sIpAddress=inet_ntoa(inAddr);
if(sIpAddress.IsEmpty())
sIpAddress=_T("没有取得");
}
return 0;
}
GetIpAddress 的一个重载:
int CClientSocket::GetIpAddress(const CString&sHostName, BYTE &f0,BYTE &f1,BYTE
&f2,BYTE &f3)
{
struct hostent FAR *lpHostEnt=gethostbyname(sHostName);
if(lpHostEnt==NULL)
{
//产生错误
f0=f1=f2=f3=0;
return GetLastError();
}
//获取IP
LPSTR lpAddr=lpHostEnt->h_addr_list[0];
if(lpAddr)
{
struct in_addr inAddr;
memmove(&inAddr,lpAddr,4);
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;
}
return 0;
214 Visual C++游戏开发技术与实例
}
CMessg 类是一个数据类,它继承于CObject。在这个程序中,让CMessg类发挥串行化数据的作
用。CMessg 类中包括了几个主要的成员变量:
CString m_strText;
int m_turn;
int m_x;
int m_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 中的核心代码如下:
class CMessg : public CObject
{
protected:
DECLARE_DYNCREATE(CMessg)
public:
CString m_strText; //聊天的内容
int m_turn; //轮到谁落子
int m_x; //落子的水平位置
int m_y; //落子的竖直位置
public:
void Init(); //初始化
public:
virtual void Serialize(CArchive& ar); //串行化数据类
};
CMessg.cpp 中的核心代码如下:
IMPLEMENT_DYNCREATE(CMessg, CObject)
void CMessg::Init() //初始化
{
m_strText = _T("");
m_x=-1;
m_y=-1;
m_turn=-1;
}
void CMessg::Serialize(CArchive& ar) //数据串行化
{
if (ar.IsStoring())
{
ar << m_strText;
ar << m_turn;
ar << m_x;
ar << m_y;
}
else
第4 章网络游戏开发215
{
ar >> m_strText;
ar >> m_turn;
ar >> m_x;
ar >> m_y;
}
}
_ Match 类(五子棋规则)
正如前面所说的,每一种游戏都有一定的规则,Match类正是五子棋的规则处理类。
在Match 类中保存着一个当前的棋盘,它是一个二维的数组int chessboard[LW][LW]。如果
chessboard[x][y]为0,则表示(x,y)的位置上没有棋子;如果chessboard[x][y]为1表示该位置上有黑子;
如果chessboard[x][y]为2,则表示该位置上有白子。
Match 类还负责判断是否能在某个位置落子,是否有人赢棋。
Cmatch 类声明如下:
#define LW 19 //棋盘的水平竖直方向的格数
class Match
{
public:
Match();
virtual ~Match();
public:
int chessboard[LW][LW]; //0 表示没有子落下;1 表示黑子落下;2 表示白子落下
public:
BOOL CanDown(int x,int y,int who); //是否能在x,y 的位置落子
BOOL IsWin(int who,int pos[5][2]); //判断是否赢棋
void Clear(); //清除棋盘内容
};
Match.cpp 中的核心代码如下(在构造函数里初始化棋盘):
Match::Match()
{
for(int i=0;i<LW;i++)
for(int j=0;j<LW;j++)
{
chessboard[i][j]=0;
}
}
Clear 函数负责清除棋盘内容:
void Match::Clear()
{
for(int i=0;i<LW;i++)
for(int j=0;j<LW;j++)
{
chessboard[i][j]=0;
}
}
CanDown 函数负责判断在点(x,y)位置是否能落子:
216 Visual C++游戏开发技术与实例
BOOL Match::CanDown(int x,int y,int who)
{
if(x<0||x>=LW||y<0||y>=LW)
return FALSE;
if(chessboard[x][y]!=0)
return FALSE;
chessboard[x][y]=who;
return TRUE;
}
判断玩家是否赢棋,如果赢棋则标注五子连珠的位置。
BOOL Match::IsWin(int who,int pos[5][2])
{
int i,j;
for(i=0;i<LW;i++)
for(j=0;j<LW;j++)
{
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(int k=0;k<5;k++)
{
pos[k][0]=i;
pos[k][1]=j+k;
}
return TRUE;
}
}
//垂直
if(i+4<LW)
{
if(chessboard[i+1][j]==who&&chessboard[i+2][j]==who&&chessboard[i+3][j]==who&&chess
board[i+4][j]==who)
{ //赢棋
//标注赢棋的关键子的位置
for(int k=0;k<5;k++)
{
pos[k][0]=i+k;
pos[k][1]=j;
}
return TRUE;
}
}
if(i+4<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)
{ //赢棋
for(int k=0;k<5;k++)//标注赢棋的关键子的位置
{
pos[k][0]=i+k;
pos[k][1]=j+k;
}
return TRUE;
}
}
//东北
if(i-4>0&&j+4<LW)
{
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)
{ //赢棋
for(int k=0;k<5;k++)//标注赢棋的关键子的位置
{
pos[k][0]=i-k;
pos[k][1]=j+k;
}
return TRUE;
}
}
}
}
return false;
}
_ 主视图FiveChessView类
FiveChessView 是程序的主视图类。它负责在主窗口中绘制棋盘和棋子,显示聊天的内容,负责对
鼠标消息进行处理等。
FiveChessView.h 中的核心代码如下:
#include "ServerSocket.h"
#include "ClientSocket.h"
#include "Match.h"
class CFiveChessDoc;
class CFiveChessView : public CView
{
public:
CString m_sMsgList; //记录聊天的内容
CServerSocket m_ListenSocket; //做服务器时的监听socket
CClientSocket m_ClientSocket; //会话socket
BOOL m_bIsClient; //是否是客户端
BOOL m_bIsInit; //是否已经初始化
int m_port; //socket 端口号
CString m_ip; //本机的IP 地址,字符串
BYTE m_bIP[4]; //本机的IP 地址,字节
218 Visual C++游戏开发技术与实例
CString m_sLocalName; //本机的名字
CEdit m_inputedit; //聊天的输入框
CEdit m_outputedit; //聊天的显示框
int m_iLineCurrentPos; //当前的显示框中的行数
public:
Match m_match; //五子棋的规则类
int m_who; //黑棋或者白棋,黑棋先行
int m_turn; //轮谁走棋
int m_POS[2]; //落子的位置
int m_winpos[5][2]; //如果赢棋,则记录关键子的位置
BOOL m_bWin; //是否赢棋
BOOL m_bOver; //结束
public:
void ProcessPendingAccept(); //作为服务器端时,接受socket 连接的处理函数
void GetLocalIP(); //得到本机的IP 地址
public:
virtual void OnDraw(CDC* pDC); //绘制棋盘和棋子
virtual void OnInitialUpdate(); //初始化处理
protected:
afx_msg void OnLButtonDown(UINT nFlags, CPointpoint);
//鼠标左键按下的消息处理函数
afx_msg void INPUTMESSAGE (); //聊天输入框的消息处理
afx_msg void OnSetclient(); //菜单项"连接服务器"的消息处理
afx_msg void OnSetserver(); //菜单项"开启服务器"的消息处理
};
FiveChessView.cpp 中的核心代码如下(构造函数负责部分初始化工作):
CFiveChessView::CFiveChessView()
{
m_bIsClient=FALSE;
m_bIsInit=FALSE;
m_bOver=FALSE;
m_bWin=FALSE;
m_turn= 1; //服务器先走,黑棋
}
OnInitialUpdate 函数负责主要的初始化工作:
void CFiveChessView::OnInitialUpdate()
{
CView::OnInitialUpdate();
static bool oninitialupdatehaving=false; //只需要初始化调用一次
if(oninitialupdatehaving==false)
{
if(::AfxSocketInit()==FALSE) //winsock 初始化
{
AfxMessageBox("socket init error");
}
GetLocalIP(); //得到本机的IP 地址
CRect rect;
this->GetWindowRect(rect);
第4 章网络游戏开发219
//创建两个动态的CEdit 控件,作为输入对话框和显示对话框。
m_outputedit.Create(ES_MULTILINE|WS_CHILD |WS_VISIBLE | WS_TABSTOP |
WS_BORDER|ES_READONLY,CRect(10,rect.bottom-200,rect.right-10,rect.bottom-140), this,1);
m_inputedit.Create(ES_MULTILINE|WS_CHILD |WS_VISIBLE | WS_TABSTOP |
WS_BORDER|ES_AUTOVSCROLL,CRect(10,rect.bottom-140,rect.right-10,rect.bottom-100),this,2);
}
}
OnDraw 函数负责绘制视图:
void CFiveChessView::OnDraw(CDC* pDC)
{
CFiveChessDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
CBrush back(RGB(125,125,20)); //绘制棋盘的刷子
pDC->SelectObject((CBrush*)&back);
CRect rect;
rect.left=LEFTDIS;rect.right=LEFTDIS+(LW-1)*30;
rect.top=TOPDIS;rect.bottom=TOPDIS+(LW-1)*30;
pDC->FillRect(&rect,&back); //绘制棋盘
CPen pen(PS_SOLID,2,RGB(25,25,255)); //绘制网格线的笔
pDC->SelectObject((CPen*)&pen);
int i,j;
CPoint pos;
for(i=0;i<LW;i++) //竖直的线
{
pos.x=LEFTDIS+30*i;
pos.y=TOPDIS;
pDC->MoveTo(pos);
pos.y=TOPDIS+(LW-1)*30;
pDC->LineTo(pos);
}
for(i=0;i<LW;i++) //水平的线
{
pos.x=LEFTDIS;
pos.y=TOPDIS+30*i;
pDC->MoveTo(pos);
pos.x=LEFTDIS+(LW-1)*30;
pDC->LineTo(pos);
}
CBrush whitebrush(RGB(255,255,255)); //绘制黑棋的刷子
CBrush blackbrush(RGB(0,0,0)); //绘制白棋的刷子
for(i=0;i<LW;i++) //扫描整个棋盘
for(j=0;j<LW;j++)
{
if(m_match.chessboard[i][j]==1) //黑棋
{
pDC->SelectObject((CBrush*)&blackbrush);
pDC->Ellipse(j*30+LEFTDIS-15,i*30+TOPDIS-15,j*30+LEFTDIS+15,i*30+TOPDIS+15);
}
220 Visual C++游戏开发技术与实例
else
if(m_match.chessboard[i][j]==2) //白棋
{
pDC->SelectObject((CBrush*)&whitebrush);
pDC->Ellipse(j*30+LEFTDIS-15,i*30+TOPDIS-15,j*30+LEFTDIS+15,i*30+TOPDIS+15);
}
}
//绘制4 个星位和一个天元
CBrush starbrush(RGB(0,0,0));
pDC->SelectObject((CBrush*)&starbrush);
j=4;i=4;
if(m_match.chessboard[i][j]==0)
pDC->Ellipse(j*30+LEFTDIS-8,i*30+TOPDIS-8,j*30+LEFTDIS+8,i*30+TOPDIS+8);
j=4;i=14;
if(m_match.chessboard[i][j]==0)
pDC->Ellipse(j*30+LEFTDIS-8,i*30+TOPDIS-8,j*30+LEFTDIS+8,i*30+TOPDIS+8);
j=9;i=9;
if(m_match.chessboard[i][j]==0)
pDC->Ellipse(j*30+LEFTDIS-8,i*30+TOPDIS-8,j*30+LEFTDIS+8,i*30+TOPDIS+8);
j=14;i=4;
if(m_match.chessboard[i][j]==0)
pDC->Ellipse(j*30+LEFTDIS-8,i*30+TOPDIS-8,j*30+LEFTDIS+8,i*30+TOPDIS+8);
j=14;i=14;
if(m_match.chessboard[i][j]==0)
pDC->Ellipse(j*30+LEFTDIS-8,i*30+TOPDIS-8,j*30+LEFTDIS+8,i*30+TOPDIS+8);
//比赛已经结束,或赢或输
if(m_bOver==TRUE)
{
CBrush redbrush(RGB(255,0,0)); //用红色的刷子显示关键的5 个棋子
pDC->SelectObject((CBrush*)&redbrush);
for(int k=0;k<5;k++)
{
i=m_winpos[k][0];
j=m_winpos[k][1];
pDC->Ellipse(j*30+LEFTDIS-15,i*30+TOPDIS-15,j*30+LEFTDIS+15,i*30+TOPDIS+15);
}
}
}
菜单项“开启服务器”的消息处理函数如下:
void CFiveChessView::OnSetserver()
{
CServerDlg dlg;
第4 章网络游戏开发221
if(dlg.DoModal()==IDOK) //服务器端口设置对话框
{
m_bIsClient=FALSE; //作为游戏的服务器端
m_bIsInit=TRUE; //已经初始化
m_port=dlg.m_iPort; //得到输入的端口号
m_ListenSocket.Init(m_port,this); //开始监听端口
}
}
菜单项“连接服务器”的消息处理函数如下:
void CFiveChessView::OnSetclient()
{
CClientDlg dlg;
int ret=dlg.DoModal(); //设置服务器的IP 和端口
if(ret==2000) //用户点击了"确定"
{
m_bIsClient=TRUE; //作为游戏的客户端
m_bIsInit=TRUE; //已经初始化
m_port=dlg.m_iPort; //得到用户输入的服务器端的端口
for(int i=0;i<4;i++)
m_bIP[i]=dlg.m_bIP[i]; //得到用户输入的服务器端的IP 地址
m_ip.Format("%d.%d.%d.%d",dlg.m_bIP[0],dlg.m_bIP[1],dlg.m_bIP[2],
dlg.m_bIP[3]);
m_ClientSocket.Create(); //创建会话socket
if(m_ClientSocket.Connect(LPCSTR(m_ip),m_port))//连接到服务器端
{
m_ClientSocket.Init(this); //初始化会话socket
m_who=2; //客户端用白子。
AfxMessageBox("成功的连接到了服务器,可以开始游戏了");
}
else
{
m_ClientSocket.Close(); //连接失败
AfxMessageBox("client connectionfailed");
}
}
}
ProcessPendingAccept 是处理客户端socket 连接的函数:
void CFiveChessView::ProcessPendingAccept()
{
if(m_ListenSocket.Accept(m_ClientSocket)==FALSE)//分配一个会话socket
{
AfxMessageBox("Server Listen SocketError");
return;
}
else
{
m_who=1; //服务器端用黑棋,黑棋先行
m_ClientSocket.Init(this); //初始化会话socket
m_outputedit.SetWindowText("有人进来了");
AfxMessageBox("有人进来了");
222 Visual C++游戏开发技术与实例
}
}
INPUTMESSAGE 函数用来处理在聊天输入框中输入的对话消息:
void CFiveChessView::INPUTMESSAGE()
{
//如果网络还没有连接好则不允许输入
if(!m_bIsInit)
{
AfxMessageBox("No Connection ");
return;
}
CString in;
CMessg msg;
m_inputedit.GetWindowText(in); //得到输入框中的文字
if(in.GetLength()<1)
{
return;
}
if(in.GetAt(in.GetLength()-1)==’\n’) //输入了回车
{
in.TrimRight(" ");
m_inputedit.SetWindowText(""); //处理掉空格字符
if(in.GetLength()>2)
{
m_sMsgList+=in; //添加聊天的内容
m_outputedit.SetWindowText(m_sMsgList); //输出到聊天显示框
m_iLineCurrentPos=m_outputedit.GetLineCount();
m_outputedit.LineScroll(m_iLineCurrentPos);//滚动到当前的位置
msg.m_strText=in;
m_ClientSocket.SendMessage(&msg); //发送聊天的内容到另外一端
}
}
}
处理鼠标左键按下的消息OnLButtonDown:
void CFiveChessView::OnLButtonDown(UINT nFlags,CPoint point)
{
//比赛是否已经结束
if(m_bOver==TRUE)
{
if(AfxMessageBox("想重新开始游戏吗?",MB_YESNO)==IDYES)
{
//重新开始游戏
m_bIsClient=FALSE;
m_bIsInit=FALSE;
m_turn=1;
m_match.Clear();
m_bWin=FALSE;
m_bOver=FALSE;
Invalidate(FALSE);
return;
第4 章网络游戏开发223
}
}
//轮到本机走棋
if(m_turn==m_who)
{
m_POS[0]=(point.y-TOPDIS)/30;
if((point.y-TOPDIS)%30>15)
m_POS[0]++; //得到点击的竖直位置
m_POS[1]=(point.x-LEFTDIS)/30;
if((point.x-LEFTDIS)%30>15)
m_POS[1]++; //得到点击的水平位置
if(m_POS[0]<0||m_POS[0]>=LW||m_POS[1]<0||m_POS[1]>=LW)
{
return;
}
//这个位置是否可以落子
if(m_match.CanDown(m_POS[0],m_POS[1],m_who)==TRUE)
{
Invalidate(FALSE); //重新绘制棋子和棋盘
m_turn=m_who%2+1; //轮到对方走棋
CMessg msg;
msg.m_turn=m_turn;
msg.m_x=m_POS[0];
msg.m_y=m_POS[1];
m_ClientSocket.SendMessage(&msg); //发送落子的位置
//判断是否赢棋
if(m_match.IsWin(m_who,m_winpos))
{
m_bWin=TRUE;
m_bOver=TRUE;
Invalidate(FALSE);
AfxMessageBox("赢了耶");
m_sMsgList+="赢了耶";
m_outputedit.SetWindowText(m_sMsgList);
}
}
}
else
{
m_sMsgList+="不该你走棋";
m_outputedit.SetWindowText(m_sMsgList);
}
CView::OnLButtonDown(nFlags, point);__
}
- 小型网络游戏实例(vc++)——网络五子棋
- 简单的小型五子棋
- 【140115】网络五子棋,VC++游戏源码
- 五子棋人机对弈——VC API实现!
- 五子棋人机对弈——VC API实现!
- 【VC++游戏开发】棋牌类游戏——五子棋
- VC++ 五子棋
- php文件操作实例——小型留言本
- android网络游戏——网络通信——epoll
- VC网络编程实例
- websocket入门(2)——使用socket.io实现网络对战版五子棋
- websocket入门(3)——网络对战版五子棋交互逻辑
- 你想让网速更快吗?小型网络改造实例
- Java实践(十一)——五子棋
- Java实践(十一)——五子棋
- java 10.29(五子棋—)
- AI—五子棋
- java网络五子棋的源代码(二)
- python的suds的soap(webserivce)客户端编程
- 【鸡兔同笼 64】
- html 文字竖排
- IIS7.0 发布第一个局域网网页
- 5个最佳的3D游戏开发工具
- 小型网络游戏实例(vc++)——网络五子棋
- UBIFS error调试总结
- PHP 日期操作
- 队列实现
- 利用十大最佳游戏开发工具开发游戏
- upload.parseRequest(request)取不到值
- 面向对象设计原则
- 软件自动化测试实施难点分析
- 算法的一些代码