0


Visual C++实现五子棋游戏项目实战三:核心算法与网络交互的实现(附源码和资源 可用于大作业)

** 需要源码和资源请点赞关注收藏后评论区留言私信~~~**

棋盘窗口类主要负责显示棋盘和棋子,同时还要处理鼠标输入信息,是整个游戏中的重点

一、棋盘窗口类的设计思想

通过分析用户的需求后,可以得出棋盘窗口类应该支持如下几个功能

能够显示棋盘和棋子图片

能够接受用户输入,并把相应的坐标转换为行列数据填充到棋子数组中,实现棋子的显示

能够处理来自网络通信的各种数据

能够调用规则类对象来判断游戏的胜负

能够支持清空游戏棋盘上的棋子

有了支持的功能列表,就需要声明一个棋盘类,代码如下所示

#ifndef __BOARD_H__
#define __BOARD_H__

#include "stdafx.h"

class CBoard:public CWnd
{
private:
    CImageList m_iml; // 棋子图像
    int m_color; // 玩家颜色
    BOOL m_bWait; // 等待标志
    BOOL m_bOldWait;    //原来的等待状态
 
public:
    CBoard();
    virtual ~CBoard();
    void RestoreWait();
    void Clear( BOOL bWait );
    void SetColor(int color);
    int  GetColor() const;
    void SetWait( BOOL bWait );
    void SetData( int x, int y, int color );
    void DrawGame();
    void Draw(int x, int y, int color);
    void Receive();
    void Over(int x, int y);

protected:
    afx_msg void OnPaint();
    afx_msg void OnLButtonUp( UINT nFlags, CPoint point );
    DECLARE_MESSAGE_MAP()
};

#endif

从上面的代码中可以看到,这个期盼类已经包含了前面设计的内容,每一个功能都由一个成员函数来实现,下面来看这个类的基础函数实现

#include "board.h"
#include "Resource.h"
#include "ConnectData.h"
#include "Rule.h"
#include "FiveChessDlg.h"

#define MAX_LEN 256                /*定义最大长度*/
//
// 构造函数,初始化棋盘数据以及图像数据
//
    m_iml.Create( 24, 24, ILC_COLOR24 | ILC_MASK, 0, 2 );
    // 载入黑、白棋子掩码位图
    CB
{

}

// 消息映射表
BEGIN_MESSAGE_MAP( CBoard, CWnd )
tObject( &bmp );
    MemDC.SelectObject( &pen );
    MemDC.SetROP2( R2_NOTXORPEN );
    // 根据棋盘数据绘制棋子
    int x, y;
    POINT pt;
    for ( y = 0; y < 15; y++ )
    {
        for ( x = 0; x < 15; x++ )
        {
            if ( -1 != m_data[x][y] )
            {
                pt.x = 12 + 25 * x;
                pt.y = 84 + 25 * y;
                m_iml.Draw( &MemDC, m_data[x][y], pt, ILD_TRANSPARENT );
            }
        }
    }
    // 完成绘制
 
    if(pDlg->m_bIsConnect)
    {
        int x, y;
        x = ( point.x - 12 ) / 25;
        y = ( point.y - 84 ) / 25;
        // 如果在(0, 0)~(14, 14)范围内,且该坐标没有落子,
        // 则落子于此,否则发声警告并退出过程
        if ( x < 0 || x > 14 || y < 0 || y > 14 || m_data[x][y] != -1 )
        {
            MessageBeep( MB_OK );
            return;
        }
        else
        {

}
//
// 清空棋盘
//
void CBoard::Clear( BOOL bWait )
{
    int x, y;
    for ( y = 0; y < 15; y++ )
    {
        for ( x = 0; x < 15; x++ )
        {
            m_data[x][y] = -1;
        }
    }
    // 设置等待标志
    m_bWait = bWait;
    Invalidate(
//
// 接收来自对方的数据
//
void CBoard::Receive()
{
    CFiveChessDlg * pDlg = (CFiveChessDlg*)AfxGetMainWnd();
    MSGSTRUCT msg;
    if(pDlg->m_sock.Receive((LPVOID)&msg, sizeof(MSGSTRUCT)) == SOCKET_ERROR)
    {
        AfxGetMainWnd()->MessageBox( _T("接收数据时发生错误,请检查您的网络连接。"), _T("错误"), MB_ICONSTOP );
        return;
    }
    switch(msg.msgType
            // 发送拒绝和棋消息
            MSGSTRUCT msg;
            msg.msgType = MSG_REFUSE_DRAW;
            pDlg->m_sock.Send( (LPCVOID)&msg, sizeof( MSGSTRUCT ) );
        }
        break;
    case MSG_AGREE_DRAW:
        pDlg->MessageBox( _T("看来真是棋逢对手,对方接受了您的和棋请求。"), _T("和棋"), MB_ICONINFORMATION );
        // 和棋后,使“重玩”菜单生效
        pDlg->SetMenuState(TRUE);
        break;
    case MSG_REFUSE_DRAW:
        pDlg->MessageBox( _T("看来对方很有信心取得胜利,所以拒绝了您的和棋请求。"),
            _T("和棋"), MB_ICONINFORMATION );
        RestoreWait();
        pDlg->SetMenuState(FALSE);
        break;
    case MSG_EXTERN:
        break;
    default:
        break;
    }

}
//
// 和棋操作
//
void CBoard::DrawGame()
{
    CFiveChessDlg * pDlg = (CFiveChessDlg*)AfxGetMainWnd();
    // 设置等待标志
    SetWait( TRUE );    
    MSGSTRUCT msg;
    msg.msgType = MSG_DRAW;
    pDlg->m_sock.Send( (LPCVOID)&msg, sizeof( MSGSTRUCT ) );
}

//
// 处理对方落子后的工作
//
void CBoard::Over(int x, int y)
{
    CRule rule;
    CFiveChessDlg *pDlg = (CFiveChessDlg *)GetParent();
    // 判断对方是否胜利
    if ( rule.Win( 1 - m_color, x, y ) == _WIN)
    {
       pDlg->MessageBox( _T("您输了,不过不要灰心,失败乃成功之母哦!"), _T("失败"), MB_ICONINFORMATION );
       // 如果是网络对战,则生效“重玩”
       if ( pDlg->m_bIsConnect )
       {
        pDlg->SetMenuState(TRUE);
       }
       return;
    }
    //判断对方是否出现禁手
    else if(rule.Win(1 - m_color, x, y) == _LOST)
    {
        pDlg->MessageBox( _T("恭喜您, 对方出现禁手输了!"), _T("胜利"), MB_ICONINFORMATION );
        // 如果是网络对战,则生效“重玩”
        if ( pDlg->m_bIsConnect )
        {
            pDlg->SetMenuState(TRUE);
        }
        return;        
    }
    m_bWait = FALSE;    
}
//
// 重新设置先前的等待标志
//
void CBoard::RestoreWait()
{
    SetWait( m_bOldWait );
}

不过要使用这个棋盘类,还必须在应用程序类的初始化函数中,注册棋盘窗口类,代码如下

// FiveChess.cpp : Defines the class behaviors for the application.
//

#include "stdafx.h"
#include "FiveChess.h"
#include "FiveChessDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/
// CFiveChessApp

BEGIN_MESSAGE_MAP(CFiveChessApp, CWinApp)
    //{{AFX_MSG_MAP(CFiveChessApp)
        // NOTE - the ClassWizard will add and remove mapping macros here.
        //    DO NOT EDIT what you see in these blocks of generated code!
    //}}AFX_MSG
    ON_COMMAND(ID_HELP, CWinApp::OnHelp)
END_MESSAGE_MAP()

/
// CFiveChessApp construction

CFiveChessApp::CFiveChessApp()
{
    // TODO: add construction code here,
    // Place all significant initialization in InitInstance
}

/
// The one and only CFiveChessApp object

CFiveChessApp theApp;

/
// CFiveChessApp initialization

BOOL CFiveChessApp::InitInstance()
{
    if (!AfxSocketInit())
    {
        AfxMessageBox(IDP_SOCKETS_INIT_FAILED);
        return FALSE;
    }

    AfxEnableControlContainer();

    // Standard initialization
    // If you are not using these features and wish to reduce the size
    //  of your final executable, you should remove from the following
    //  the specific initialization routines you do not need.

#ifdef _AFXDLL
    Enable3dControls();            // Call this when using MFC in a shared DLL
#else
    Enable3dControlsStatic();    // Call this when linking to MFC statically
#endif

    // 注册棋盘窗口类
    WNDCLASS wc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hbrBackground = (HBRUSH)GetStockObject( WHITE_BRUSH );
    wc.hCursor = LoadCursor( IDC_ARROW );
    wc.hIcon = NULL;
    wc.hInstance = AfxGetInstanceHandle();
    wc.lpfnWndProc = ::DefWindowProc;
    wc.lpszClassName = _T("ChessBoard");
    wc.lpszMenuName = NULL;
    wc.style = 0;
    AfxRegisterClass( &wc );

    CFiveChessDlg dlg;
    m_pMainWnd = &dlg;
    int nResponse = dlg.DoModal();
    if (nResponse == IDOK)
    {
        // TODO: Place code here to handle when the dialog is
        //  dismissed with OK
    }
    else if (nResponse == IDCANCEL)
    {
        // TODO: Place code here to handle when the dialog is
        //  dismissed with Cancel
    }

    // Since the dialog has been closed, return FALSE so that we exit the
    //  application, rather than start the application's message pump.
    return FALSE;
}

二、网络交互的设计与实现

网络交互类是整个游戏的核心内容之一,其主要提供双击通信的基础,并且控制游戏的交互过程

为了方便使用和实现,游戏中的网络交互类采用继承CAsyncSocket类的方法实现,通过这种方式就可以很方便的进行Winsock网络通信,而且实现的代码也比较精简

网络交互的算法实现如下

#ifndef __CONNECT_H__
#define __CONNECT_H__

#include <afxsock.h>

class CConnect: public CAsyncSocket 
{
public:
    CConnect();                //构造函数
    virtual ~CConnect();    //析构函数
    // Implementation
protected:
    virtual void OnAccept( int nErrorCode );
    virtual void OnConnect( int nErrorCode );
    virtual void OnReceive( int nErrorCode );
    virtual void OnClose( int nErrorCode );
};

#endif
#include "Connect.h"
#include "FiveChessDlg.h"
#include "Board.h"

CConnect::CConnect()
{
}

CConnect::~CConnect()
{
}

/
// CFiveSocket member functions

void CConnect::OnAccept( int nErrorCode )
{
    CFiveChessDlg * pDlg = (CFiveChessDlg*)AfxGetMainWnd();
    pDlg->Accept();
    pDlg->SetMenuState(FALSE);
}

void CConnect::OnClose( int nErrorCode )
{
    CFiveChessDlg * pDlg = (CFiveChessDlg*)AfxGetMainWnd();

    pDlg->MessageBox( _T("对方已经离开游戏,改日再较量不迟。"), _T("五子棋"), MB_ICONINFORMATION);

    pDlg->SetMenuState(TRUE);

    pDlg->m_board.SetWait(TRUE);

    pDlg->m_conncet.Close();

    pDlg->m_sock.Close();

    pDlg->m_bIsConnect = FALSE;
    
}

void CConnect::OnConnect( int nErrorCode )
{
    CFiveChessDlg * pDlg = (CFiveChessDlg*)AfxGetMainWnd();
    pDlg->Connect();
    pDlg->SetMenuState(FALSE);    
}

void CConnect::OnReceive( int nErrorCode )
{

    CBoard *pBoard = (CBoard *)AfxGetMainWnd()->GetDlgItem( IDC_BOARD );
    pBoard->Receive();
}

值得注意的是,在设计这个类时,一定要同时设计客户端与主机端的功能,这样才能在游戏中进行客户机与主机的通信

创作不易 觉得有帮助请点赞关注收藏~~~

标签: 游戏 c++ 网络交互

本文转载自: https://blog.csdn.net/jiebaoshayebuhui/article/details/129241912
版权归原作者 showswoller 所有, 如有侵权,请联系我们删除。

“Visual C++实现五子棋游戏项目实战三:核心算法与网络交互的实现(附源码和资源 可用于大作业)”的评论:

还没有评论