小学期windows程序设计课作业,虽然不喜欢windows的东西,但是对API的东西完全没有抵抗力。
个人作品,资源和框架抄的windows的源代码,剩下功能都是自己实现和添加的。
http://download.youkuaiyun.com/detail/lvlawliet/4553381
上面是资源连接,不需要积分,我好吧。
来分析一下这个程序,先从main.cpp开始。
void OnCreate(HWND hwnd)
{
KillTimer(hwnd, 100);
b_IfFace = FALSE;
IsLoadMine = FALSE;
IsOver = FALSE;
timer = FALSE;
//加载位图
g_hBmMine = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_MINE));
g_BitFace = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_FACE));
g_BitNumber = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_NUMBER));
g_FaceNUM = 4;
g_Number_1 = 11;
g_Number_2 = 11;
g_Number_3 = 11;
//初始化位图
for (int nxIndex = 0; nxIndex < nXClient; nxIndex++)
{
for (int nyIndex = 0; nyIndex < nYClient; nyIndex++)
{
g_Flag[nxIndex][nyIndex] = IDBITNUM_INIT;
g_Bit[nxIndex][nyIndex] = IDBITNUM_INIT;
}
}
//初始化雷区
int row, clm;
srand((unsigned)GetTickCount());
for (int nIndex = 0; nIndex < nMaxMine; nIndex++)
{
row = rand() % nXClient;
clm = rand() % nYClient;
while (g_Flag[row][clm] == IDBITNUM_MINE)
{
row = rand() % nXClient;
clm = rand() %nYClient;
}
g_Flag[row][clm] = IDBITNUM_MINE;
}
}
位图是你在资源文件里定义好的,使用方法:看好你需要图片里第几个小格的,基本上位图需要的图片都是几个相同规格的小图片组成的,从上到下,第一个编号是0,第二个是1,以此类推,当前位置需要哪个图片,就赋值给位图变量编号即可。
例如
g_Bit[nxIdex][nyIndex] = IDBITNUM_INIT;
IDBITUN_INIT表示没有点开小格的图片,这样就将雷区初始化了。
void OnDLGCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
{
int flag = 0;
RECT rect;
HWND p_hwnd = GetParent(hwnd);
GetWindowRect(p_hwnd, &rect);
CHAR DlgText[256] = {0};
switch (LOWORD(wParam))
{
case IDOK:
SendDlgItemMessage(hwnd, ID_EDITHEITH, WM_GETTEXT, 5, (LPARAM)DlgText);
nYClient = cToNumber(DlgText, 0);
if (nYClient > 0 && nYClient <= 39);
else
nYClient = 10, flag = 1;
SendDlgItemMessage(hwnd, ID_EDITWIDTH, WM_GETTEXT, 5, (LPARAM)DlgText);
nXClient = cToNumber(DlgText, 0);
if (nXClient > 0 && nXClient <= 62);
else
nXClient = 10, flag = 1;
SendDlgItemMessage(hwnd, ID_EDITMINE, WM_GETTEXT, 5, (LPARAM)DlgText);
nMaxMine = cToNumber(DlgText, 0);
if (nMaxMine > 0 && nMaxMine <= nXClient * nYClient);
else
nMaxMine = 10, flag = 1;
if (flag == 1)
MessageBox(NULL, "你丫连100以内的非零自然数都输入不对,脑残片吃多了吧!好好看说明书去。", "你脑残吧!!!", MB_OK);
MoveWindow(p_hwnd, rect.left, rect.top, nXClient * 16 + 36,
nYClient * 16 + 126, TRUE);
OnCreate(p_hwnd);
InvalidateRgn(p_hwnd, NULL, TRUE);
EndDialog(hwnd, 100);
break;
case IDCANCEL:
EndDialog(hwnd, 100);
break;
}
}
BOOL CALLBACK ModalProc(HWND hwnd,
UINT nMsg,
WPARAM wParam,
LPARAM lParam)
{
switch (nMsg)
{
case WM_COMMAND:
OnDLGCommand(hwnd, wParam, lParam);
break;
case WM_SYSCOMMAND:
if (SC_CLOSE == wParam)
{
EndDialog(hwnd, 100);
}
}
return 0;
}
void OnModal(HWND hwnd, WPARAM wParam)
{
DialogBox(g_hInst, MAKEINTRESOURCE(IDD_SETTING), hwnd, ModalProc);
}
关于菜单栏里面自定义窗口的调出,用DialogBox调出ModalProc函数即可。
void FindMine1(int x, int y)
{
if ((x < nXClient && y < nYClient) && (x >= 0 && y >= 0))
{
if (g_Flag[x][y] == 0)
{
g_Flag[x][y] = IDBITNUM_SPASE;
g_Bit[x][y] = IDBITNUM_SPASE;
FindMine1(x + 1, y);
FindMine1(x - 1, y);
FindMine1(x, y + 1);
FindMine1(x, y - 1);
FindMine1(x + 1, y - 1);
FindMine1(x - 1, y - 1);
FindMine1(x + 1, y + 1);
FindMine1(x - 1, y + 1);
}
else if (g_Flag[x][y] != IDBITNUM_MINE)
{
g_Bit[x][y] = g_Flag[x][y];
}
}
return;
}
void FindMine(int x, int y)
{
for (int row = 0; row < nXClient; row++)
{
for (int clm = 0; clm < nYClient; clm++)
{
if (g_Flag[row][clm] == IDBITNUM_INIT)
{
for (int i = 0; i < 3; ++i)
{
for (int j = 0; j < 3; ++j)
{
if (g_Flag[row - 1 + i][clm - 1 + j] == IDBITNUM_MINE)
{
g_Flag[row][clm]++;
}
}
}
}
}
}
FindMine1(x, y);
}
从当前非雷点扩展开图,只需要递归搜索出当前点所能到达所有的有数方格及其之内的空格即可。
void IsMine()
{
for (int row = 0; row < nXClient; row++)
{
for (int clm = 0; clm < nYClient; clm++)
{
for (int i = 0; i < 3; ++i)
{
for (int j = 0; j < 3; ++j)
{
if (g_Flag[row - 1 + i][clm - 1 + j] == IDBITNUM_MINE)
{
g_Bit[row - 1 + i][clm - 1 + j] = g_Flag[row - 1 + i][clm - 1 + j];
}
}
}
if (g_Flag[row][clm] == IDBITNUM_MINE)
g_Bit[row][clm] = g_Flag[row][clm];
else
if (g_Flag[row][clm] != IDBITNUM_MINE && g_Bit[row][clm] == 14)
g_Bit[row][clm] = 12;
}
}
IsOver = TRUE;
}
如果失败,显示所有雷,如果一个空格标记为小旗,那么要显示为X雷,所以需要加判断对该位置位图重新赋值编号。
void DrawMine(HDC hdc)
{
HDC hBmpDC = CreateCompatibleDC(hdc); //创建DC
HBITMAP hOldBmp = (HBITMAP) //保存旧位图
SelectObject(hBmpDC, g_hBmMine);
//绘制位图
for (int nxIndex = 0; nxIndex < nXClient; nxIndex++)
{
for (int nyIndex = 0; nyIndex < nYClient; nyIndex++)
{
int nXPos = nxIndex * 16 + 14;
int nYPos = nyIndex * 16 + 72;
BitBlt(hdc, nXPos, nYPos, 16, 16, hBmpDC, 0,
g_Bit[nxIndex][nyIndex] * 16, SRCCOPY);
}
}
SelectObject(hBmpDC, hOldBmp); //恢复旧位图
DeleteDC(hBmpDC);
}
这个就是实现位图贴到窗口的过程,期间贴的是g_Bit数组的编号,所以,如果你想记录信息用g_Flag数组,如果要显示用g_Bit数组。
void checkwin()
{
int flag = 1;
for (int row = 0; row < nXClient; row++)
{
for (int clm = 0; clm < nYClient; clm++)
{
if (g_Bit[row][clm] == 0 && g_Flag[row][clm] != IDBITNUM_MINE)
flag = 0;
}
}
if (flag == 1)
{
for (int row = 0; row < nXClient; row++)
{
for (int clm = 0; clm < nYClient; clm++)
{
if (g_Flag[row][clm] == IDBITNUM_MINE)
g_Bit[row][clm] = 14;
}
}
g_FaceNUM = 1;
IsOver = TRUE;
}
}
void OnLButtonUp(HWND hwnd, WPARAM wParam, LPARAM lParam)
{
int nXPos = LOWORD(lParam) - 14;
int nYPos = HIWORD(lParam) - 72;
int row = nXPos / 16;
int clm = nYPos / 16;
if (IsOver == FALSE)
{
if ((row < nXClient && clm < nYClient) && (row >= 0 && clm >= 0))
{
if (g_Bit[row][clm] == 14);
else
if (g_Flag[row][clm] == IDBITNUM_MINE)
{
IsMine();
g_Bit[row][clm] = 11;
g_FaceNUM = 2;
}
else
{
g_FaceNUM = 4;
FindMine(row, clm);
checkwin();
}
}
}
InvalidateRgn(hwnd, NULL, FALSE);
}
因为没有实现鼠标滑动,所以末日down点坐标和up点坐标一样,先求出当前坐标,之后判断是否是雷,如果不是就展开图,最后判断一下是否当前状态已经赢了(checkwin函数),同时要注意你在鼠标的操作也伴随着Face的改变,所以不同结果也要给g_FaceNUM不同的编号。
void DrawShell(HDC hdc)
{
HPEN hPen = CreatePen(PS_SOLID, 3, RGB(255, 255, 255));
HPEN hOldPen = (HPEN)SelectObject(hdc, hPen);
HBRUSH hBrush = CreateSolidBrush(RGB( 179, 179, 179));
HBRUSH hOldBrush = (HBRUSH)SelectObject(hdc, hBrush);
MoveToEx(hdc, g_Width - 13, 13, NULL);
LineTo(hdc, g_Width - 13, 60);
MoveToEx(hdc, 13, 60, NULL);
LineTo(hdc, g_Width - 13, 60);
MoveToEx(hdc, 1, 1, NULL);
LineTo(hdc, g_Width, 1);
MoveToEx(hdc, 1, 0, NULL);
LineTo(hdc, 1, g_Heigth);
MoveToEx(hdc, 13, g_Heigth - 9, NULL);
LineTo(hdc, g_Width - 13, g_Heigth - 9);
MoveToEx(hdc, g_Width - 13, 72, NULL);
LineTo(hdc, g_Width - 13, g_Heigth - 10);
SelectObject(hdc, hOldBrush);
DeleteObject(hBrush);
SelectObject(hdc, hOldPen);
DeleteObject(hPen);
}
void DrawShell1(HDC hdc)
{
HPEN hPen = CreatePen(PS_SOLID, 3, RGB(150, 150, 150));
HPEN hOldPen = (HPEN)SelectObject(hdc, hPen);
HBRUSH hBrush = CreateSolidBrush(RGB( 200, 200, 200));
HBRUSH hOldBrush = (HBRUSH)SelectObject(hdc, hBrush);
MoveToEx(hdc, 13, 13, NULL);
LineTo(hdc, g_Width - 13, 13);
MoveToEx(hdc, 13, 12, NULL);
LineTo(hdc, 13, 60);
SelectObject(hdc, hOldBrush);
DeleteObject(hBrush);
SelectObject(hdc, hOldPen);
HPEN hPen1 = CreatePen(PS_SOLID, 3, RGB(150, 150, 150));
HPEN hOldPen1 = (HPEN)SelectObject(hdc, hPen1);
MoveToEx(hdc, g_Width - 13, 69, NULL);
LineTo(hdc, 11, 69);
MoveToEx(hdc, 12, g_Heigth - 10, NULL);
LineTo(hdc, 12, 69);
SelectObject(hdc, hOldPen1);
DeleteObject(hPen);
}
绘制窗口,因为现实有些立体感,所有需要在边框用不同颜色的线段勾勒....学过美术的同学想必很好理解,所有这两个函数主要作用就是用不同颜色的先勾勒上面的窗口,使其显得更有立体感。
主要函数就是这些了,下面是resource.rc里面的东西,.rc文件很好创建,如果你很熟悉也可以直接txt写。
//Microsoft Developer Studio generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
/
#undef APSTUDIO_READONLY_SYMBOLS
/
// Chinese (P.R.C.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)
#ifdef _WIN32
LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED
#pragma code_page(936)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/
//
// TEXTINCLUDE
//
1 TEXTINCLUDE DISCARDABLE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE DISCARDABLE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
3 TEXTINCLUDE DISCARDABLE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/
//
// Dialog
//
IDD_SETTING DIALOG DISCARDABLE 0, 0, 129, 85
STYLE DS_CONTEXTHELP | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "自定义雷区"
FONT 9, "宋体"
BEGIN
DEFPUSHBUTTON "确定",IDOK,80,20,40,16
PUSHBUTTON "取消",IDCANCEL,80,46,40,16
LTEXT "高度(&H):",112,10,22,35,10,NOT WS_GROUP
EDITTEXT ID_EDITHEITH,46,20,25,12
LTEXT "宽度(&W):",113,10,37,35,10,NOT WS_GROUP
EDITTEXT ID_EDITWIDTH,46,35,25,12
LTEXT "雷数(&M):",111,10,52,35,10,NOT WS_GROUP
EDITTEXT ID_EDITMINE,46,50,25,12
END
IDD_ABOUT DIALOG DISCARDABLE 0, 0, 150, 68
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "关于扫雷"
FONT 10, "System"
BEGIN
LTEXT "仅仅测试,众多BUG,望且见谅。",112,10,10,120,100,NOT WS_GROUP
LTEXT "——————BY L.Lawliet", 120, 50,40, 120, 100, NOT WS_GROUP
END
/
//
// Menu
//
IDR_MAIN MENU FIXED IMPURE
BEGIN
POPUP "游戏(&G)"
BEGIN
MENUITEM "开局(&N)\tF2", ID_START
MENUITEM SEPARATOR
MENUITEM "初级(&B)", ID_FIRST
MENUITEM "中级(&I)", ID_MID
MENUITEM "高级(&E)", ID_HIGHT
MENUITEM "自定义(&C)...", ID_DIY
MENUITEM SEPARATOR
MENUITEM "保存(&S)", ID_SIN
MENUITEM "读取(&L)", ID_LOAD
//MENUITEM "颜色(&L)", ID_COLOR
MENUITEM "声音(&M)", ID_SOUND
MENUITEM SEPARATOR
MENUITEM "扫雷英雄榜(&T)...", ID_HERO
MENUITEM SEPARATOR
MENUITEM "退出(&X)", ID_EXIT
END
POPUP "帮助(&H)"
BEGIN
//MENUITEM "目录(&C)\tF1", ID_DIR
//MENUITEM "查找帮助主题(&S)...", ID_HELPINFO
MENUITEM "帮助(&H)", ID_HELP
MENUITEM SEPARATOR
MENUITEM "关于扫雷(&A)...", ID_ABOUT
END
END
/
//
// Bitmap
//
IDB_MINE BITMAP FIXED IMPURE "./res/mine.bmp"
IDB_FACE BITMAP FIXED IMPURE "./res/face.bmp"
IDB_NUMBER BITMAP FIXED IMPURE "./res/number.bmp"
/
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_MAIN ICON DISCARDABLE "./res/main.ico"
/
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO DISCARDABLE
BEGIN
IDD_ABOUT, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 163
TOPMARGIN, 7
BOTTOMMARGIN, 61
END
END
#endif // APSTUDIO_INVOKED
/
//
// Accelerator
//
501 ACCELERATORS FIXED IMPURE
BEGIN
VK_F1, 590, VIRTKEY
VK_F2, 510, VIRTKEY
END
#endif // Chinese (P.R.C.) resources
/
#ifndef APSTUDIO_INVOKED
/
//
// Generated from the TEXTINCLUDE 3 resource.
//
/
#endif // not APSTUDIO_INVOKED
主要的是位图图片和ID的连接,还有菜单栏。