一步一步实现五子棋2

上一章我们实现了棋盘的绘制,现在来实现用鼠标下棋的功能吧。

首先添加一个Engine类,然后添加若干方法和成员,代码如下:

#ifndef FIVE_ENGINE_H

#define FIVE_ENGINE_H

 

#include <vector>

 

using namespacestd;

 

// 游戏状态

enum GAME_STATUS

{

   GAME_READY = 0,   // 游戏准备

   GAME_WAITING,     // 电脑等待中

   GAME_THINKING,    // 电脑思考中

   GAME_OVER         // 游戏结束

};

 

// 棋盘交叉点属性

enum CHESS_TYPE

{

   CHESS_SPACE = 0,    // 无棋子

   CHESS_BLACK,        // 此处有黑子

   CHESS_WHITE         // 此处有白子

};

 

// 棋盘交叉点结构 

struct CHESS_POINT

{

   int x;        // 水平方向位置

   int y;        // 垂直方向位置

   int type;     // 棋子类型

};

 

class Engine

{

public:

   Engine(void);

   ~Engine(void);

 

   void Init();

   void StartGame();

 

   // 用户落子

   BOOL UserDown(int x,inty);

 

   vector<CHESS_POINT*>getChessList() {returnm_chessList;}

   

private:

   int m_gameState;    // 游戏状态

   int m_userType;     // 用户持子类型 1表示持黑子 2表示持白子

   int m_AIType;       // 电脑持子类型

   CHESS_POINT m_chessTable[15][15];   // 棋盘状态

   vector<CHESS_POINT*>m_chessList;   // 已落子列表

};

#endif

 

以上基本满足了对棋盘和棋子状态的保存。接下来就要添加鼠标事件来完成落子了。

切换到资源视图,右键对话框,选择属性,右侧面板会出现属性框,点击消息,添加WM_LBUTTONUP事件,然后添加相应的处理代码:

void CFiveDlg::OnLButtonUp(UINTnFlags,CPointpoint)

{

   // TODO: 在此添加消息处理程序代码和/或调用默认值

 

   int x= (point.x+m_blockSize / 2 -m_left)/m_blockSize;

   int y= (point.y+m_blockSize / 2 -m_top)/m_blockSize;

 

   if (m_engine->UserDown(x,y))

   {

       // 重绘

       Invalidate();

   }

 

   CDialog::OnLButtonUp(nFlags,point);

}

 

Engine::UserDown的实现如下:

BOOL Engine::UserDown(intx,inty )

{

   // 不在棋盘上,返回

   if ((x> 14) || (x < 0) || (y > 14) || (y< 0))

   {

       return FALSE;

   }

 

   // 该位置有子,返回

   if (m_chessTable[x][y].type !=CHESS_SPACE)

   {

       return FALSE;

   }

 

   m_chessTable[x][y].type =m_userType;

   m_chessList.push_back(&m_chessTable[x][y]);

 

   return TRUE;

}

 

绘制棋子的函数要做相应的修改:

void CFiveDlg::DrawChess(Graphics *g)

{

   if ((m_whiteImg==NULL) || (m_blackImg==NULL))

   {

       return;

   }

 

   int chessLeft= m_left - m_blockSize/ 2;

   int chessTop= m_top - m_blockSize/ 2;

   int chessSize= m_blockSize;

 

   // 从m_engine中获取棋子信息,然后一个一个绘制

   vector<CHESS_POINT*>chessList =m_engine->getChessList();

   vector<CHESS_POINT*>::iteratoritor =chessList.begin();

   while (itor!=chessList.end())

   {

       if ((*itor)->type ==CHESS_WHITE)

       {

            g->DrawImage(m_whiteImg,chessLeft + (*itor)->x * m_blockSize,chessTop + (*itor)->y *m_blockSize,chessSize,chessSize);

       }

       else if((*itor)->type=CHESS_BLACK)

       {

            g->DrawImage(m_blackImg,chessLeft + (*itor)->x * m_blockSize,chessTop + (*itor)->y *m_blockSize,chessSize,chessSize);

       }

 

       itor++;

   }

}


  做好上面的一切后运行程序,看看效果吧。

看,已经能够用鼠标下棋了。可能有同学要问了,怎么都是黑子啊?不急不急,电脑现在智商为零,还不会下棋呢,后面我会让它越来越聪明的,人机对弈的日子不太遥远。

有一个问题,在运行时我发现每下一颗子,画面重绘时会有闪烁现象,我是绝对不能容忍这种伤眼睛的问题存在的,明天重点解决这个问题,不知道有没有高手能够提供解决方法。


继续昨天的问题,大家应该都想到了用双缓存就可以解决闪烁的问题,下面我对自己的绘制部分代码做下修改。

// 建立一块虚拟画布
        Bitmap bmp(m_width, m_height);
        Graphics bmpGraphics(&bmp);

        // 绘制棋盘
        DrawChessBoard(&bmpGraphics);


        // 绘制棋子
        DrawChess(&bmpGraphics);

        // 下面是在对话框上绘图了
        CPaintDC dc(this);
        Graphics graphics(dc.m_hDC);

        // 建立一个CacheBitmap用于快速绘图
        CachedBitmap cachedBmp(&bmp, &graphics);

        graphics.DrawCachedBitmap(&cachedBmp,0,0);  

  试一下效果,还是有闪烁现象抓狂。为了解决这个问题,在网上找了许多资料,经大神指点知道了原来调用Invalidate()之后会发出两个消息WM_ERASEBKGND和WM_PAINT。WM_ERASEBKGND消息会擦除背景,先擦除后描画导致了闪烁现象。解决方法是截获WM_ERASEBKGND,代码如下:

BOOL CFiveDlg::OnEraseBkgnd(CDC* pDC)
{
    // TODO: 在此添加消息处理程序代码和/或调用默认值
   
//return CDialog::OnEraseBkgnd(pDC);

  return TRUE;

}

再试一下效果,真的一点都不闪了!!!除此之外,调用Invalidate(FALSE)进行重绘的效果也一样。




  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值