加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

C++ SDK五子棋制作教程

(2011-12-18 12:29:17)
标签:

五子棋制作教程

    这个学期学习了Windows  GDI的一点粗浅入门的功夫,都到期末了,就用所学到的知识做了一个人——人对战的五子棋,虽然简单,但是也是费了一番功夫的,现在发到博客上,供人斧正,如果你是一个想自己动手制作五子棋的C++新手(和我一样http://www/uc/myshow/blog/misc/gif/E___6725EN00SIGG.gifSDK五子棋制作教程" TITLE="C++ SDK五子棋制作教程" />),那么这篇博文多少也是有一点借鉴作用的,如果你是高手的话,那么请不要嘲笑小弟技术的薄弱(我今年大二,技术上尚有许多不成熟的地方)。

    制作五子棋之前,首先是要安装一个编译工具,起码得是Visual C++6.0,这是最基本的了,不过,我使用的是Visual Studio 2010,这个编译器功能十分强大,可以开发多种语言支持下的项目,好了,现在开始介绍五子棋制作得过程了。

    首先,创建一个项目,至于怎么创建,这里就不多说了,因为每个人的编译器不一样,制作五子棋,首先要确定功能,最好要有项目文档,写项目文档的目的是为了能够很好地提高开发的效率,下面是我写的项目文档:

   http://s9/middle/9bf44d30gb4567016f9a8&690SDK五子棋制作教程" TITLE="C++ SDK五子棋制作教程" />
   C++程序良好的变成习惯是,能够很好的运用到类,下面是我的项目类编排:

   http://s12/middle/9bf44d30gb456e3243bdb&690SDK五子棋制作教程" TITLE="C++ SDK五子棋制作教程" />


   我的五子棋分为三个阶段,这里只介绍第一阶段的代码:

   首先我们得创建一个主文件,我把它命名为FiveChessMain.CPP

   这里要涉及到一点点Win32编程的知识了,其实如果我们想做游戏的话,无需纠结于Win32API函数,只需要了解一下其基本的框架,只要掌握一些必要的函数用法就行了,其他的,Windows系统会帮你处理的,我们所要做的,是如何将游戏做得更加生动有趣,而不是死抠技术细节。

   下面是五子棋主文件的代码:

在此之前,我们得先导入相关BMP格式的图片

#define WIN32_LEAN_AND_MEAN //不使用MFC命令;

//定义头文件
#include <Windows.h>
#include <WindowsX.h>
#include <stdio.h>
#include <math.h>
#include "Rule.h"
#include "resource.h"
#include "InitDraw.h"

#define WINCLASS "wncss"
HWND main_hwnd=NULL;
static int xPos,yPos;
HBITMAP backBmp,blackBmp,whiteBmp;
HINSTANCE m_hinstance=NULL;
//棋子的颜色0为白色,1为黑色;
static int value=0;
//定义棋盘的横坐标和纵坐标;
static int cx,cy;

//定义规则类对象;
CRule rule;

//定义键盘响应事件;
#define KEYDOWN(vk_code)((GetAsyncKeyState(vk_code)&0x8000)?1:0)

//定义棋盘信息
static CRule::ChessInfo m_data[16][16];
static int count=0;
 int wcount=0;//黑棋计数变量;
 int bcount=0;//白棋计数变量;
 int win=0; //获取win函数返回值变量;

//定义事件处理器;
LRESULT CALLBACK WinProc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam)
{
 PAINTSTRUCT ps;//设置窗体绘图变量;
 HDC hdc;//设置图形设备窗体句柄;
 HDC mdc;
 
 //初始化落子信息-1表示棋盘未有棋子,颜色未设定;
 if(count==0)
 {
 for(int j=0;j<=15;j++)
  for(int i=0;i<=15;i++)
  {
   m_data[j][i].IsExist=-1;
  }
  count++;
 }
 switch(msg)
 {
 case WM_CREATE:
  int screenWidth,screenHeight;
  RECT rect;
  //获取屏幕尺寸;
  screenWidth=GetSystemMetrics(SM_CXSCREEN);
  screenHeight=GetSystemMetrics(SM_CYSCREEN);
  //获取窗体尺寸;
  GetWindowRect(hwnd,&rect);
  rect.left=(screenWidth-rect.right)/2;
  rect.top=(screenHeight-rect.bottom)/2;
  //显示窗体;
  SetWindowPos(hwnd,HWND_TOP,rect.left,rect.top,rect.right,rect.bottom,SWP_SHOWWINDOW);
  break;
 case WM_PAINT:
  hdc=BeginPaint(hwnd,&ps);
  EndPaint(hwnd,&ps);
  break;
 case WM_DESTROY:
  PostQuitMessage(0);
  break;
  //鼠标左键单击事件;
 case WM_LBUTTONUP:
  {
  if(value==0)
   value=1;
  else
   value=0;
  xPos=LOWORD(lparam);
  yPos=HIWORD(lparam);
  //定义落子的x轴坐标;
  for(int i=25;i<=370;i+=25)
  {
   if(xPos<i+25)
   {
     xPos=i;
     break;
   }
  }

  //定义落子的y轴坐标;
  for(int j=97;j<=470;j+=25)
  {
   if(yPos<j+25)
   {
     yPos=j;
     break;
   }
  }
  //获得棋盘坐标;
  cx=(xPos-25)/25+1;
  cy=(yPos-97)/25+1;
  if(m_data[cx][cy].IsExist==-1)
  {
  }
  else
  {
   MessageBox(hwnd,"您不能在这里落子!","提示",MB_OK);
   if(value==0)
    value=1;
   else
    value=0;
  }
  
  }
  break;
 case WM_COMMAND:
  switch(LOWORD(wparam))
  {
  case ID_GAME_START:
   {
    CInitDraw init_draw;
    init_draw.Draw(hwnd,m_hinstance);
    rule.InitData(m_data);
    win=0;
    cx=0;
    cy=0;
   }
   break;
  case ID_GAME_EXIT:
   PostQuitMessage(0);
   break;
  case ID_GAME_INFO:
   MessageBox(hwnd,"DirectX 游戏开发小组组员制作。","说明",MB_OK);
   break;
  default:break;
  }
  break;
 default:break;
 }
 return(DefWindowProc(hwnd,msg,wparam,lparam));
}


//定义主窗体事件;
int WINAPI WinMain(HINSTANCE hinstance,HINSTANCE prevhinstance,LPSTR ncmdline,int ncmdshow)
{
 WNDCLASSEX winclass;   //定义窗体类函数;
 HWND hwnd;
 MSG msg;
 HDC hdc;
 HDC mdc,back_dc;

 winclass.cbClsExtra=0;
 winclass.cbWndExtra=0;
 winclass.cbSize=sizeof(WNDCLASSEX);
 winclass.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);
 winclass.hCursor=LoadCursor(NULL,IDC_ARROW);
 winclass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
 winclass.hIconSm=LoadIcon(NULL,IDI_APPLICATION);
 winclass.hInstance=hinstance;
 winclass.lpfnWndProc=WinProc;
 winclass.lpszClassName=WINCLASS;
 winclass.lpszMenuName=NULL;
 winclass.style=CS_HREDRAW|CS_VREDRAW|CS_OWNDC|CS_DBLCLKS;

 //注册窗体类;
 if(!RegisterClassEx(&winclass))
  return 0;
 

 //创建窗体;
 if(!(hwnd=CreateWindowEx(
  NULL,
  WINCLASS,
  "五子棋",
  WS_CAPTION|WS_VISIBLE,
  0,0,
  400,515,
  NULL,
  NULL,
  hinstance,
  NULL)))
  return 0;
  main_hwnd=hwnd;
  //加载菜单
 HMENU hmenu=LoadMenu(hinstance,MAKEINTRESOURCE(IDR_MAIN_MENU));
 SetMenu(main_hwnd,hmenu);
 m_hinstance=hinstance;

 hdc=GetDC(main_hwnd);
 HBITMAP hbmp;
 //设置内存与显示协同;
 mdc=CreateCompatibleDC(hdc);
 hbmp=LoadBitmap(hinstance,MAKEINTRESOURCE(IDB_BITMAP_TABLE));
 SelectObject(mdc,hbmp);
 whiteBmp=LoadBitmap(hinstance,MAKEINTRESOURCE(IDB_BITMAP_WHITE));
 blackBmp=LoadBitmap(hinstance,MAKEINTRESOURCE(IDB_BITMAP_BLACK));

 while(true)
 {
  
  if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
  {
   if(msg.message==WM_QUIT)
    break;
   TranslateMessage(&msg);
   DispatchMessage(&msg);
  }

  if(KEYDOWN(VK_ESCAPE))
   SendMessage(hwnd,WM_CLOSE,0,0);

  //先下黑棋;
  if(value==1)
  {
   BitBlt(hdc,0,0,395,470,mdc,0,0,SRCCOPY);
   SelectObject(mdc,blackBmp);
   //在棋盘未落子,且未有一方获胜,还有棋子在棋盘范围内的情况下绘制棋子;
   if(m_data[cx][cy].IsExist==-1&&win!=1&&cx<15&&cy<15&&cx>0&&cy>0)
   {
   BitBlt(hdc,xPos,yPos,25,25,mdc,0,0,SRCAND);
   BitBlt(hdc,xPos,yPos,25,25,mdc,0,0,SRCPAINT);
   m_data[cx][cy].IsExist=1;
   win=rule.Win(main_hwnd,m_data);
   }
  }
  else
  {
   BitBlt(hdc,0,0,395,470,mdc,0,0,SRCCOPY);
   SelectObject(mdc,whiteBmp);
   //在棋盘未落子,且未有一方获胜,还有棋子在棋盘范围内的情况下绘制棋子;
   if(m_data[cx][cy].IsExist==-1&&win!=1&&cx<15&&cy<15&&cx>0&&cy>0)
   {
   BitBlt(hdc,xPos,yPos,25,25,mdc,0,0,SRCAND);
   BitBlt(hdc,xPos,yPos,25,25,mdc,0,0,SRCPAINT);
   m_data[cx][cy].IsExist=0;
   win=rule.Win(main_hwnd,m_data);
   }
   
  }
  
 }
 DeleteObject(mdc);
 ReleaseDC(hwnd,hdc);
 return(msg.wParam);
}

   怎样?晕了吧,呵呵,不要紧,如果你对以上的代码有很大的疑惑,那么请先打好Windows编程必要的基础再来看吧,最低限度,你得知道如何去使用GDI去绘制简单的图形。

接下来我们来看初始化类:InitDraw

下面是InitDraw.h的代码:

#pragma once
#include <Windows.h>
#include "resource.h"
class CInitDraw
{
public:
 CInitDraw(void);
 ~CInitDraw(void);
 //重画棋盘并且棋盘初始化;
 void Draw(HWND hwnd,HINSTANCE hinstance);
};

 

InitDraw.CPP文件代码:

#include "InitDraw.h"
#include "resource.h"

CInitDraw::CInitDraw(void)
{
}


CInitDraw::~CInitDraw(void)
{
}

//定义初始化函数;
void CInitDraw::Draw(HWND hwnd,HINSTANCE hinstance)
{
 HBITMAP hbmp;
 HDC hdc,mdc;  //定义目标设备和内存设备;
 hdc=GetDC(hwnd);
 mdc=CreateCompatibleDC(hdc);//设置协同等级;
 hbmp=LoadBitmap(hinstance,MAKEINTRESOURCE(IDB_BITMAP_TABLE));
 SelectObject(mdc,hbmp);
 BitBlt(hdc,0,0,395,470,mdc,0,0,SRCCOPY);
 DeleteObject(mdc);
 ReleaseDC(hwnd,hdc);
}

这个类比较简单,仅仅是定义重画事件,这里的Draw函数应当在菜单响应事件(WM_COMMAND)里的ID_GAME_START中调用,用以重新开始游戏时,重画棋盘。]

接下来介绍整个五子棋游戏中的核心算法类:CRule

下面是代码示例:

Rule.h

#pragma once
#include <Windows.h>
class CRule
{
public:
 CRule(void);
 ~CRule(void);
 //定义棋盘信息的数据结构;
 typedef struct tagChessInfo
 {
  int IsExist;
 }ChessInfo;
 //定义棋盘信息数组;
 ChessInfo m_data[16][16];
 //定义判断胜负的函数;
 int Win(HWND hwnd,ChessInfo m_data[16][16]);
 void InitData(ChessInfo m_data[16][16]);
private:
 int wcount; //判断白棋胜负的变量;
 int bcount; //判断黑棋胜负的变量;
 //判断第一行是否有黑棋;
 int bxfirst,byfirst;
 //判断第一行/向的顶端是否为白棋;
 int wxfirst,wyfirst;
};

 

Rule.CPP

#include "Rule.h"


CRule::CRule(void)
{
 //初始化棋子变量;
 wcount=0;
 bcount=0;

 //判断第一行是否有棋子;
 bxfirst=0;
 byfirst=0;

 //判断第一行/向的顶端是否为白棋;
  wxfirst=0;
  wyfirst=0;
}


CRule::~CRule(void)
{
}

//初始化棋盘;
void CRule::InitData(ChessInfo m_data[16][16])
{
 for(int j=0;j<=15;j++)
  for(int i=0;i<=15;i++)
  {
   m_data[j][i].IsExist=-1;
  }
}
//定义判断胜负的函数;
int CRule::Win(HWND hwnd,ChessInfo m_data[16][16])
{
 //横向判断;
 for(int j=1;j<=15;j++)
  for(int i=1;i<=15;i++)
  {
   //判断白棋是否获胜;
   if(m_data[i][j].IsExist==0)
   {
    if(m_data[i-1][j].IsExist==m_data[i][j].IsExist)
     wcount++;
    if(wcount>=4)
    {
     MessageBox(hwnd,"白棋获胜!","提示",MB_OK);
     return 1;
    }
    //如果棋子中间断层,则判断棋子是否连珠的变量归零;
    if(m_data[i-1][j].IsExist!=m_data[i][j].IsExist)
     if(wcount>0)
      wcount=0;
   }
   //判断黑棋是否获胜
   if(m_data[i][j].IsExist==1)
   {
    if(m_data[i-1][j].IsExist==m_data[i][j].IsExist)
     bcount++;
    if(bcount>=4)
    {
     MessageBox(hwnd,"黑棋获胜!","提示",MB_OK);
     return 1;
    }
    if(m_data[i-1][j].IsExist!=m_data[i][j].IsExist)
     if(bcount>0)
      bcount=0;
   }
   
  }
  wcount=0;//白棋计数变量归零;
  bcount=0;//黑棋计数变量归零;

  //纵向判断
  for(int i=1;i<=15;i++)
   for(int j=1;j<=15;j++)
   {
    //判断白棋是否获胜;
    if(m_data[i][j].IsExist==0)
    {
     if(m_data[i][j-1].IsExist==m_data[i][j].IsExist)
      wcount++;
     if(wcount>=4)
     {
      MessageBox(hwnd,"白棋获胜!","提示",MB_OK);
      return 1;
     }
     //如果棋子中间断层,则判断棋子是否连珠的变量归零;
     if(m_data[i][j-1].IsExist!=m_data[i][j].IsExist)
      if(wcount>0)
       wcount=0;
    }

    //判断黑棋是否获胜;
    if(m_data[i][j].IsExist==1)
    {
     if(m_data[i][j-1].IsExist==m_data[i][j].IsExist)
      bcount++;
     if(bcount>=4)
     {
      MessageBox(hwnd,"黑棋获胜!","提示",MB_OK);
      return 1;
     }
     if(m_data[i][j-1].IsExist!=m_data[i][j].IsExist)
      if(bcount>0)
       bcount=0;
    }
   }
   wcount=0;//白棋计数变量归零;
   bcount=0;//黑棋计数变量归零;

   //判断“/”向的左上角部分;
   for(int i=5;i<=15;i++)
    for(int j=1,k=i;j<=15,k>0;j++,k--)
    {
     //判断白棋是否获胜;
     if(m_data[k][j].IsExist==0)
     {
      if(m_data[k][j].IsExist==m_data[k+1][j-1].IsExist)
        wcount++;
       if(wcount>=4)
       {
        MessageBox(hwnd,"白棋获胜!","提示",MB_OK);
        return 1;
       }
       if(m_data[k][j].IsExist!=m_data[k+1][j-1].IsExist)
        if(wcount>0)
         wcount=0;
     }

     //判断黑棋是否获胜;
     if(m_data[k][j].IsExist==1)
     {
      if(m_data[k][j].IsExist==m_data[k+1][j-1].IsExist)
       bcount++;
      if(bcount>=4)
      {
       MessageBox(hwnd,"黑棋获胜!","提示",MB_OK);
       return 1;
      }
      if(m_data[k][j].IsExist!=m_data[k+1][j-1].IsExist)
        if(bcount>0)
         bcount=0;
     }
    }

    wcount=0;//白棋计数变量归零;
    bcount=0;//黑棋计数变量归零;

    //判断‘/’方向的右下角部分;
    for(int j=2;j<=10;j++)
     for(int i=14,k=j;i>=2,k<=14;i--,k++)
     {
      //判断白棋是否获胜;
      if(m_data[i][k].IsExist==0)
      {
       if(m_data[i][k].IsExist==m_data[i+1][k-1].IsExist)
        wcount++;
       if(wcount>=4)
       {
        MessageBox(hwnd,"白棋获胜!","提示",MB_OK);
        return 1;
       }
       if(m_data[i][k].IsExist!=m_data[i+1][k-1].IsExist)
        if(wcount>0)
         wcount=0;
      }

      //判断黑棋是否获胜;
      if(m_data[i][k].IsExist==1)
      {
       if(m_data[i][k].IsExist==m_data[i+1][k-1].IsExist)
        bcount++;
       if(bcount>=4)
       {
        MessageBox(hwnd,"黑棋获胜!","提示",MB_OK);
        return 1;
       }
       if(m_data[i][k].IsExist!=m_data[i+1][k-1].IsExist)
        if(bcount>0)
         bcount=0;
      }
     }
    
    wcount=0;//白棋计数变量归零;
    bcount=0;//黑棋计数变量归零;

    //判断‘\’方向右上角部分;
    for(int i=10;i>0;i--)
     for(int j=1,k=i;j<=14,k<=14;j++,k++)
     {
      //判断白棋是否获胜;
      if(m_data[k][j].IsExist==0)
      {
       if(m_data[k][j].IsExist==m_data[k-1][j-1].IsExist)
        wcount++;
       if(wcount>=4)
       {
        MessageBox(hwnd,"白棋获胜!","提示",MB_OK);
        return 1;
       }
       if(m_data[k][j].IsExist!=m_data[k-1][j-1].IsExist)
        if(wcount>0)
         wcount=0;
      }

      //判断黑棋是否获胜;
      if(m_data[k][j].IsExist==1)
      {
       if(m_data[k][j].IsExist==m_data[k-1][j-1].IsExist)
        bcount++;
       if(bcount>=4)
       {
        MessageBox(hwnd,"黑棋获胜!","提示",MB_OK);
        return 1;
       }
       if(m_data[k][j].IsExist!=m_data[k-1][j-1].IsExist)
        if(bcount>0)
         bcount=0;
      }
     }

     wcount=0;//白棋计数变量归零;
     bcount=0;//黑棋计数变量归零;

     //判断‘\’方向的左下角部分;
     for(int j=2;j<=14;j++)
      for(int i=1,k=j;i<14,k<=14;i++,k++)
      {
       //判断白棋是否获胜;
       if(m_data[i][k].IsExist==0)
       {
        if(m_data[i][k].IsExist==m_data[i-1][k-1].IsExist)
         wcount++;
        if(wcount>=4)
        {
         MessageBox(hwnd,"白棋获胜!","提示",MB_OK);
         return 1;
        }
        if(m_data[i][k].IsExist!=m_data[i-1][k-1].IsExist)
         if(wcount>0)
          wcount=0;
       }

       //判断黑棋是否获胜;
       if(m_data[i][k].IsExist==1)
       {
        if(m_data[i][k].IsExist==m_data[i-1][k-1].IsExist)
         bcount++;
        if(bcount>=4)
        {
         MessageBox(hwnd,"黑棋获胜!","提示",MB_OK);
         return 1;
        }
        if(m_data[i][k].IsExist!=m_data[i-1][k-1].IsExist)
         if(bcount>0)
          bcount=0;
       }
      }

      return 0;
}

总算是将所有的代码示例出来了,其实我也想写得更详细一些,但是时间不允许,至于那些想自己动手制作五子棋的朋友来说,这只能是给一点参考,最好还是完全自己写出代码来,不要一味地按照别人的思路来走,这样对你没什么帮助的。下面是运行结果:

http://s6/middle/9bf44d30gb456cd33a8f5&690SDK五子棋制作教程" TITLE="C++ SDK五子棋制作教程" />

游戏执行中:

http://s12/middle/9bf44d30gb456d1a8bd7b&690SDK五子棋制作教程" TITLE="C++ SDK五子棋制作教程" />

http://s15/middle/9bf44d30gb456d53ef16e&690SDK五子棋制作教程" TITLE="C++ SDK五子棋制作教程" />

游戏获胜:

http://s7/middle/9bf44d30gb456d8626086&690SDK五子棋制作教程" TITLE="C++ SDK五子棋制作教程" />

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有