一步一步实现扫雷游戏(C语言实现)(三)

使用WIN32API连接窗口

此项目相关博文链接

一步一步实现扫雷游戏(C语言实现)(一)

一步一步实现扫雷游戏(C语言实现)(二)

一步一步实现扫雷游戏(C语言实现)(三)

一步一步实现扫雷游戏(C语言实现)(四)

 

  首先,我弄个主窗口出来,没有用到MFC,直接调用API函数实现,先看看代码吧:

///////////////////////////////////////
//
//主函数:扫雷
//
///////////////////////////////////////

#include
<windows.h>
#include
<stdio.h>
#include
"DrawMap.h"//见下文
#include
"def.h"

int m =10, n =10;
int map[MAX_X][MAX_Y];
int Global_x[MAX_X], Global_y[MAX_Y];


LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
WINGDIAPI BOOL WINAPI MoveToEx(HDC hdc,
int x, int y, LPPOINT lppt);//移动当前画笔的位置
WINGDIAPI BOOL WINAPI LineTo(HDC hdc, int x, int y);//用来画直线的函数
WINGDIAPI HPEN WINAPI CreatePen(int iStyle, int cWidth, COLORREF color);




int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine,
int iCmdShow)
{
init();
//初始化数组(地雷分布
int x_position, y_position, x_size, y_size;
set_position_size(
&x_position, &y_position, &x_size, &y_size);

static TCHAR szAppName[] = TEXT ("MainWin") ;
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ;

wndclass.style
= CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc
= WndProc ;
wndclass.cbClsExtra
=0 ;
wndclass.cbWndExtra
=0 ;
wndclass.hInstance
= hInstance ;
wndclass.hIcon
= LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor
= LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground
= (HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName
= NULL ;
wndclass.lpszClassName
= szAppName ;

if (!RegisterClass (&wndclass))
{
MessageBox (NULL, TEXT (
"This program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return0 ;
}

hwnd
= CreateWindow (szAppName, // window class name
TEXT ("扫雷游戏——The ClearMines Game"), // window caption
WS_OVERLAPPED | \
WS_CAPTION
| \
WS_SYSMENU
| \
WS_MINIMIZEBOX,
// window style
x_position, // initial x position
y_position, // initial y position
x_size, // initial x size
y_size, // initial y size
NULL, // parent window handle
NULL, // window menu handle
hInstance, // program instance handle
NULL) ; // creation parameters
ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (
&msg) ;
DispatchMessage (
&msg) ;
}
return msg.wParam ;
}

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_PAINT:
paint_map(hwnd); //自定义的画图函数
return0;

case WM_LBUTTONDOWN: //单击鼠标
int x=LOWORD(lParam);//x,y为鼠标当前的位置坐标
int y=HIWORD(lParam);
left_key(hwnd, x, y);//自定义的响应鼠标左键的函数
break;

case WM_DESTROY:
PostQuitMessage (
0) ;
return0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}

主窗口图:

现在,看看DrawMap.h文件的一些自定义函数的声明:

#include <windows.h>
#include
<stdio.h>
#include
"NumMines.h"//这个文件就是前两篇随笔中的那个后台实现算法的,等下也放上来

//全局变量
externint map[MAX_X][MAX_Y];
externint m, n;
externint Global_x[MAX_X], Global_y[MAX_Y];

//自定义函数
void paint_map(HWND hwnd);//又看到它了,那就看代码吧
BOOL DrawGrid(HDC hdc,
int x1, int y1, int x2, int y2);//这个函数是实现在上面函数的
//设置窗口位置和大小
void set_position_size(int* p_x_position, int* p_y_position, int* p_x_size, int* p_y_size);
void left_key(HWND hwnd, int x, int y);
void DrawRec(HWND hwnd, HDC hdc, int i, int j);
RECT rectRec(HWND hwnd,
int x, int y);//x,y为小矩形左上角的坐标

void paint_map(HWND hwnd);//又看到它了,那就看代码吧

//DrawMap.cpp

////////////////////////////////////////////////////////////
//
//画图
//
////////////////////////////////////////////////////////////
void paint_map(HWND hwnd)
{
HDC hdc ;
PAINTSTRUCT ps ;
RECT rect ;
int x1,y1,x2,y2;
int x_position, y_position, x_size, y_size;
set_position_size(
&x_position, &y_position, &x_size, &y_size);

int frame_width = GetSystemMetrics(SM_CXSIZEFRAME); //边框宽度
int caption_width = GetSystemMetrics(SM_CYCAPTION); //标题栏宽度
int menu_high = GetSystemMetrics(SM_CYMENU); //菜单高度
x1 = caption_width;
y1
= caption_width;
x2
= x_size - caption_width - frame_width;
y2
= y_size -2*caption_width - frame_width;

hdc
= BeginPaint (hwnd, &ps) ;
GetClientRect (hwnd,
&rect) ;
DrawGrid(hdc, x1, y1, x2, y2);
EndPaint (hwnd,
&ps) ;
}

///////////////////////////////
//
//画格子
//
//////////////////////////////
BOOL DrawGrid(HDC hdc, int x1, int y1, int x2, int y2)
{
int i, j;
POINT ptLeftTop;
BOOL tmp1, tmp2;
int tmp_x1;
int tmp_y1;
int tmp_x2;
int tmp_y2;

//画横线
tmp_x1 = x1;
tmp_y1
= y1;
tmp_x2
= tmp_x1+((x2-x1)/m)*m;
for (i =0; i <= m; i++)
{
if (i != m)
{
Global_y[i]
= tmp_y1;
}
ptLeftTop.x
= tmp_x1;
ptLeftTop.y
= tmp_y1;
tmp1
= MoveToEx(hdc,ptLeftTop.x,ptLeftTop.y,NULL);
ptLeftTop.x
= tmp_x2;
ptLeftTop.y
= tmp_y1;
tmp2
= LineTo(hdc,ptLeftTop.x,ptLeftTop.y);
tmp_y1
+= (y2-y1)/n;
}

//画竖线
tmp_x1 = x1;
tmp_y1
= y1;
tmp_y2
= tmp_y1+((y2-y1)/m)*m;
for (j =0; j <= n; j++)
{
if (j != n)
{
Global_x[j]
= tmp_x1;
}
ptLeftTop.x
= tmp_x1;
ptLeftTop.y
= tmp_y1;
tmp1
= MoveToEx(hdc,ptLeftTop.x,ptLeftTop.y,NULL);
ptLeftTop.x
= tmp_x1;
ptLeftTop.y
= tmp_y2;
tmp2
= LineTo(hdc,ptLeftTop.x,ptLeftTop.y);
tmp_x1
+= (x2-x1)/m;
}
if (tmp1 == FALSE || tmp2 == FALSE)
{
return FALSE;
}
return TRUE;
}
 
///////////////////////////////////////
//
//响应左键事件
//这里有问题啊!!
//单击鼠标左键不能再格子里画东西啊
//求帮忙解答啊
//////////////////////////////////////
void left_key(HWND hwnd, int x, int y)//x,y为鼠标当前的位置坐标
{
int tmp_x = x, tmp_y = y, i, j;
POINT lpPoint;
PAINTSTRUCT ps ;
HDC hdc ;
RECT rect ;

for (i =0; i < m-1; i++)
{
if (tmp_x > Global_x[i] && tmp_x < Global_x[i+1]) break;
}
for (j =0; j < n-1; j++)
{
if (tmp_y > Global_y[j] && tmp_y < Global_y[j+1]) break;
}

/***************************************************
left : 指定矩形框左上角的x坐标
top: 指定矩形框左上角的y坐标
right: 指定矩形框右下角的x坐标
  bottom:指定矩形框右下角的y坐标
***************************************************
*/
rect
= rectRec(hwnd, tmp_x, tmp_y);
hdc
= GetDC(hwnd);
COLORREF Minescolor
= SetTextColor(hdc,RGB(255,0,0)); //设置地雷颜色
if (map[i][j] == MINES)
{
DrawText (hdc, TEXT (
"*"), -1, &rect,
DT_SINGLELINE
| DT_CENTER | DT_VCENTER);
GetClientRect(hwnd,
&rect);
DrawText (hdc, TEXT (
"GAME OVER!"), -1, &rect,
DT_SINGLELINE
| DT_CENTER | DT_VCENTER);
ReleaseDC(hwnd,hdc);
MessageBox(hwnd, TEXT(
"再玩一次?"),TEXT("退出"), MB_RETRYCANCEL|MB_ICONQUESTION);
}
elseif (map[i][j] ==0)
{
//ReleaseDC(hwnd,hdc);
DrawRec(hwnd, hdc, i, j);
}
elseif (map[i][j] >0&& map[i][j] <9)
{
TCHAR str_tmp[
10];
sprintf(str_tmp,
"%d",map[i][j]);
DrawText (hdc, TEXT (str_tmp),
-1, &rect,
DT_SINGLELINE
| DT_CENTER | DT_VCENTER);
//ReleaseDC(hwnd,hdc);
}
}

//画0,表示该处为0个地雷
 //感觉要使用递归,可就是无法实现
void DrawRec(HWND hwnd, HDC hdc, int i, int j)
{
TCHAR str_tmp[
1];
RECT rect
= rectRec(hwnd, Global_x[i], Global_y[j]); //当前小矩形的坐标

//hdc = GetDC(hwnd);
if (map[i][j] ==0)
{
sprintf(str_tmp,
"%d",map[i][j]);
DrawText (hdc, TEXT (str_tmp),
-1, &rect,
DT_SINGLELINE
| DT_CENTER | DT_VCENTER) ;
}
elseif (map[i][j] >0&& map[i][j] <9)
{
sprintf(str_tmp,
"%d",map[i][j]);
DrawText (hdc, TEXT (str_tmp),
-1, &rect,
DT_SINGLELINE
| DT_CENTER | DT_VCENTER) ;
//ReleaseDC(hwnd,hdc);
return;
}
}

////////////////////////////////////////
//
//获取小矩形坐标
//
////////////////////////////////////////
RECT rectRec(HWND hwnd, int l_x, int l_y)//x,y为小矩形左上角的坐标
{
RECT rect;
int x1,y1,x2,y2;//窗口坐标
int x_position, y_position, x_size, y_size;
set_position_size(
&x_position, &y_position, &x_size, &y_size);

int frame_width = GetSystemMetrics(SM_CXSIZEFRAME); //边框宽度
int caption_width = GetSystemMetrics(SM_CYCAPTION); //标题栏宽度
int menu_high = GetSystemMetrics(SM_CYMENU); //菜单高度
x1 = caption_width;
y1
= caption_width;
x2
= x_size - caption_width - frame_width;
y2
= y_size -2*caption_width - frame_width;

rect.left
= l_x;
rect.top
= l_y;
rect.right
= l_x+((x2-x1)/m)*m;
rect.bottom
= l_y+((y2-y2)/m)*m;
return rect;
}

其他的代码也不上来:

//NumMines.h
#include <windows.h>

#include
<stdio.h>
#include
<string.h>
#include
"time.h"
#include
"stdlib.h"

#define MAX_X 100 //行坐标最大值
#define MAX_Y 100 //纵坐标最大值
#define MINES -1 //地雷

externint m, n;
externint map[MAX_X][MAX_Y];


void set_mines(int num_mines);
int round_num_mines(int i,int j);
BOOL init(
void);

//NumMines.cpp

View Code
//NumMines.cpp

#include
"NumMines.h"

#include
<windows.h>

#include
<stdio.h>
#include
<string.h>
#include
"time.h"
#include
"stdlib.h"

/*******************************************************************
初始化地雷分布位置和个数
函数功能:根据设置的地雷个数和分布地图(map,数组)给出分布好了地雷的数组
函数原型:void set_mines( int num_mines)
参数:(in)—— int num_mines
********************************************************************
*/
void set_mines(int num_mines)
{
int num =0;
int i,j;

while (num <= num_mines)
{
srand(time(
0));
//rand()%n 取(0,n-1)的随机数
i = rand() % m;
j
= rand() % n;
//如果出现相同的情况呢?,没事,再循环几次,直到有了足够的地雷为止
if (i<0|| i>m || j<0|| j>n || map[i][j] == MINES)
{
continue;
}
map[i][j]
= MINES;
num
++;//判断地雷个数
}
}

/****************************************************************************
返回周围地雷个数的函数
函数原型: int round_num_mines(int i,int j);
参 数: int i, int j为当前的坐标
返回值类型: int 返回该坐标处周围的地雷数
返回值情况:(1)返回1-8代表周围有1-8个地雷;
(2)返回0代表周围没有地雷;
(3)返回*代表此坐标时地雷;
*****************************************************************************
*/
int round_num_mines(int i,int j)
{
if (map[i][j] == MINES)
{
return MINES;
}

int dir[8][2] = {{-1,-1},{-1,0},{-1,1},{0,1},{1,1},{1,0},{1,-1},{0,-1}};
int k =0, num_mines =0;

for (k =0; k <8; k++)
{
if (map[i+dir[k][0]][j+dir[k][1]] =='*')
{
num_mines
++;
}
}
return num_mines;
}

BOOL init(
void)
{
memset(map,
0, sizeof(map));
int i, j;
int flag =0;

set_mines((m
*n)/10);//55个地雷

for (i=0; i<m; i++)
{
for (j=0; j<=n; j++)
{
map[i][j]
= round_num_mines(i, j);
flag
=1;
}
}
if (1== flag)
{
return TRUE;
}
return FALSE;
}
//DEF.H


#ifndef _DEF_
#define _DEF_

#define MAX_X 100 //行坐标最大值
#define MAX_Y 100 //纵坐标最大值
#define MINES -1 //地雷
#define DEF_M //默认行坐标
#define DEF_N //默认列坐标

#endif /* _DEF_ */

希望朋友们知道的帮忙解答解答,谢谢

 

posted @ 2011-03-31 11:29  涵曦  阅读(3265)  评论(0编辑  收藏  举报