择善教育公开课
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ 生成的包含文件。
// 供 BrainMaster.rc 使用
//
#define IDD_DIALOG_MAIN 101
#define IDC_BTN_START 1001
#define IDC_BUTTON_CHANGE_COLOR 1002
#define IDC_SLIDER_DIF 1003
#define IDC_STATIC_DIF 1004
#define IDC_COLORNOW 1005
#define IDC_GAME_AREA 1006
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 102
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1007
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
#include <stdio.h>
#include <windows.h>
#include <CommCtrl.h>
#include <list>
using namespace std;
#include "resource.h"
typedef struct _gameRect{
RECT rect; //保存一个色块的位置信息
COLORREF rgb;// 保存一个色块的颜色信息
bool Win;// 保存这个色块是否唯一的颜色,即正确色块
}GameRect;
typedef list<GameRect> GameList; //游戏色块链表数据类型
GameList g_GameList; // 链表
HINSTANCE g_hInstance;
COLORREF g_ColorNow; // 全局变量保存当前颜色
unsigned int g_GameDiff;//当前游戏难度
unsigned int g_Stage; // 当前第几关?
// 生成随机数 ...0~base
DWORD GetRandrom(DWORD base)
{
DWORD result;
__asm{
rdtsc
mov result,eax
}
return result%base;
}
// 生成本次游戏的数据
void OnInitStageData(HWND hWnd)
{
g_GameList.clear(); // 清空原来的链表信息
DWORD nItemNum = g_Stage + 3; // 当前关卡需要显示多少个色块?
if (nItemNum>8)
{
nItemNum = 8;
}
HWND GameWnd = GetDlgItem(hWnd, IDC_GAME_AREA); // 获取游戏区域的句柄
RECT WndRect;
GetWindowRect(GameWnd, &WndRect); //获取游戏区域的大小
DWORD nWidth = WndRect.right - WndRect.left;
DWORD nHeight = WndRect.bottom - WndRect.top;
DWORD WinItemIndex = GetRandrom(nItemNum); // 生成一个随机数,指示哪一个色块是正确滴
DWORD nItemCntRow = 3;
DWORD nItemCntColumn = (nItemNum % 3) ? nItemNum / 3 + 1 : nItemNum / 3;//计算需要多少行色块
DWORD nItemWidth = (nWidth - 10) / nItemCntRow; // 每个色块的宽度
DWORD nItemHeight = (nHeight - 10) / nItemCntColumn;// 每个色块的高度
for (DWORD i = 0; i <= nItemNum;i++)
{
GameRect gRect;
gRect.rect.left = 10 + (i % 3)*nItemWidth;
gRect.rect.right = gRect.rect.left + nItemWidth - 10;
gRect.rect.top = 10 + (i / 3)*nItemHeight;
gRect.rect.bottom = gRect.rect.top + nItemHeight - 10;
gRect.rgb = g_ColorNow; // 正常的颜色
gRect.Win = false; //大部分的色块不是正确答案
if (i == WinItemIndex)
{
byte r = GetRValue(g_ColorNow) > 125 ? GetRValue(g_ColorNow) - g_GameDiff : GetRValue(g_ColorNow) + g_GameDiff;
byte g = GetGValue(g_ColorNow) > 125 ? GetGValue(g_ColorNow) - g_GameDiff : GetGValue(g_ColorNow) + g_GameDiff;
byte b = GetBValue(g_ColorNow) > 125 ? GetBValue(g_ColorNow) - g_GameDiff : GetBValue(g_ColorNow) + g_GameDiff;
gRect.rgb = RGB(r, g, b);
gRect.Win = TRUE;
}
g_GameList.push_back(gRect);
}
return;
}
void OnShowStage(HWND hWnd)
{
HWND GameWnd = GetDlgItem(hWnd, IDC_GAME_AREA);
HDC hdc = GetDC(GameWnd);
GameList::iterator iter = g_GameList.begin();
// 遍历链表,取出每个色块的信息,并按信息去进行绘图
for (; iter != g_GameList.end();iter++)
{
GameRect gameRect = *iter;
HBRUSH hBrush = CreateSolidBrush(gameRect.rgb);
HBRUSH hOldBrush = (HBRUSH)SelectObject(hdc, hBrush);
Rectangle(hdc, gameRect.rect.left, gameRect.rect.top, gameRect.rect.right, gameRect.rect.bottom);
SelectObject(hdc, hOldBrush);
}
ReleaseDC(GameWnd, hdc);
return;
}
// 功能:更新当前颜色
bool OnChangeColor(HWND hWnd)
{
HWND hColorWnd = GetDlgItem(hWnd, IDC_COLORNOW);//获取当前颜色指示器控件的句柄
// 初始化一个结构体...
CHOOSECOLOR chs;
memset(&chs, 0, sizeof(CHOOSECOLOR));
chs.lStructSize = sizeof(CHOOSECOLOR);
chs.hwndOwner = hColorWnd;
chs.rgbResult = g_ColorNow;
chs.lpCustColors = &g_ColorNow;
chs.Flags = CC_ANYCOLOR | CC_RGBINIT;
ChooseColor(&chs);
g_ColorNow = chs.rgbResult; //获取到选择的颜色
HDC hdc = GetDC(hColorWnd);
RECT rect;
GetWindowRect(hColorWnd, &rect);//获取的是指示器控件的大小
// 创建一个笔刷
HBRUSH hBrush = CreateSolidBrush(g_ColorNow);
SelectObject(hdc, hBrush);
Rectangle(hdc, 0, 0, rect.right - rect.left, rect.bottom - rect.top);
ReleaseDC(hColorWnd, hdc);
return true;
}
bool OnStartGame(HWND hWnd)
{
if (g_ColorNow == 0) // 如果点击开始游戏的时候,没有选择颜色,先要求选择一次
{
OnChangeColor(hWnd);
}
OnInitStageData(hWnd);
OnShowStage(hWnd);
return false;
}
// 初始化的函数
bool OnInitDialog(HWND hWnd)
{
g_Stage = 1;
return false;
}
// 检查一个点是否在规定矩形内
bool PointInRect(HWND hWnd,POINT pt, RECT rect)
{
return pt.x < (rect.right - rect.left) && pt.y < (rect.bottom - rect.top);
}
// 检查一个点是否是全局链表中的正确色块信息
bool PointIsRight(HWND hWnd, POINT pt)
{
//遍历链表,对比每个色块的位置信息与鼠标点
HWND gameWnd = GetDlgItem(hWnd, IDC_GAME_AREA);
RECT WndRect;
GetWindowRect(gameWnd, &WndRect);
// 将屏幕坐标转换成客户区坐标并减去
POINT lefttop;
lefttop.x = WndRect.left;
lefttop.y = WndRect.top;
ScreenToClient(hWnd, &lefttop);
//570427370
//
pt.x -= lefttop.x;
pt.y -= lefttop.y;
bool bIsRight = false;
GameList::iterator iter = g_GameList.begin();
for (; iter != g_GameList.end();iter++)
{
GameRect gameRect = *iter;
// 如果鼠标点在矩形区域内,且矩形区域是不同颜色滴...找到了正确答案
if (PointInRect(hWnd,pt,gameRect.rect) && gameRect.Win)
{
bIsRight = true;
break;
}
}
return bIsRight;
}
// Windows通过消息来驱动,
INT_PTR CALLBACK GameProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
RECT gameArea;
switch (uMsg)
{
case WM_INITDIALOG://首次创建窗口时产生
OnInitDialog(hWnd);
break;
case WM_LBUTTONUP:
POINT pt;
GetCursorPos(&pt);//获取当前鼠标的位置
ScreenToClient(hWnd, &pt);//鼠标点也转成客户区坐标系
GetWindowRect(GetDlgItem(hWnd, IDC_GAME_AREA), &gameArea);
if (PointInRect(hWnd,pt,gameArea)) // 检查鼠标点是否在游戏区域内
{
if (PointIsRight(hWnd, pt))
{
g_Stage++; // 当前关卡加1
SendMessage(hWnd, WM_COMMAND, IDC_BTN_START, 0);//模拟鼠标点击窗口中开始游戏按钮
}
else
MessageBox(hWnd, L"选择错误", L"Wrong", MB_OK | MB_ICONINFORMATION);
}
break;
case WM_NOTIFY://获取通知消息
if (wParam == IDC_SLIDER_DIF)
{
g_GameDiff = (unsigned int)SendMessage(GetDlgItem(hWnd, IDC_SLIDER_DIF), TBM_GETPOS, 0, 0);
if (g_GameDiff <1)
{
g_GameDiff = 1;
}
char szTmp[MAX_PATH];
sprintf_s(szTmp, MAX_PATH, "当前游戏难度:%d", 100-g_GameDiff);
SetDlgItemTextA(hWnd, IDC_STATIC_DIF, szTmp);
}
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDC_BUTTON_CHANGE_COLOR:
OnChangeColor(hWnd);
break;
case IDC_BTN_START:
OnStartGame(hWnd);
break;
default:
break;
}
break;
case WM_CLOSE:
case WM_DESTROY:
PostQuitMessage(0);
return TRUE;
default:
break;
}
return FALSE;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
g_hInstance = hInstance;
HWND hWnd = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_DIALOG_MAIN), NULL, GameProc);
if (hWnd == 0)
{
MessageBox(0, L"创建窗口失败", 0, 0);
return -1;
}
// 获取窗口大小,将窗口设置到整个屏幕的中心
RECT rect;
GetWindowRect(hWnd, &rect);
int nScreenX = GetSystemMetrics(SM_CXSCREEN); //获取屏幕的宽度
int nScreenY = GetSystemMetrics(SM_CYSCREEN); //获取屏幕的高度
SetWindowPos(hWnd, HWND_TOP, nScreenX / 2 - (rect.right - rect.left) / 2,
nScreenY / 2 - (rect.bottom - rect.top) / 2, 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW);//不改变窗口大小,只将窗口置顶显示,并移动到屏幕中心
MSG msg;
while (GetMessage(&msg,0,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
鼠标点击色块区域的算法,还需进一步的修改。