这个学期学习了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五子棋制作教程" />
加载中,请稍候......