win32编程之俄罗斯方块

因为把目标定在了游戏上,最近在学习win32编程

经过一段时间的学习,开始进行编程实现俄罗斯方块,记录一下其中遇到的一些问题

一开始是看网上的教程学习的,但是做完一部分之后发现   会有闪屏的情况   所以又去网上搜索了一下发现要用到双缓冲。

注意:这段开始正确性有待考证!

我一开始的时候是把

drawTeris();

drawBackGround();

drawBlocked();

都放在了WM_PAINT事件里

而且里面都用了双缓冲来绘制,结果导致后面闪屏更加频繁,后来把所有的绘制动作都交由一个缓冲区来处理,然后删掉其他函数中的双缓冲相关代码并加入drawBackGround中,这样在WM_PAINT事件中只需要调用一次drawBackground就行了  而且也没发现有闪屏了。

另外还发现一个比较奇葩的问题:

一个用了BOOL类型的变量后面把他当作bool类型进行memcpy的时候会出问题

贴上在网上找到的资料:

windows为了兼容问题定义的基础变量。

typedef unsigned long        DWORD;

typedef int                  BOOL;

typedef unsigned char        BYTE;

typedef unsigned short       WORD;

typedef float                FLOAT;

typedef FLOAT                *PFLOAT;

typedef BOOL near            *PBOOL;

typedef BOOL far             *LPBOOL;

typedef BYTE near            *PBYTE;

typedef BYTE far             *LPBYTE;

typedef int near             *PINT;

typedef int far              *LPINT;

根据上面这段可以发现其实BOOL是个int类型的

附上  代码

tetris.h

#pragma once

#include "resource.h"

//函数声明
void checkComplite();  //查看一行是否能消去  采用从上往下的消法,消去一行后把上面的每行都往下移,但是我感觉效率有点低,以后看能不能有点改进
void drawBlocked(HDC hdc);		//绘制当前已经存在砖块的区域
void DrawBackGround(HDC hdc);		//绘制背景
void outPutBoxInt(int num);		//自定义的弹窗函数  用于调试
void outPutBoxString(TCHAR str[1024]);
void setRandomT();		//随机生成一个方块用作下一次掉落
void init_game();		//初始化
void fillBlock();		//到达底部后填充矩阵
void RotateTeris(BOOL bTeris[4][4]);		//旋转矩阵
void DrawTeris(HDC mdc);	//绘制正在下落的方块
void drawNext(HDC hdc);	//绘制下一个将要掉落的方块
void drawScore(HDC hdc);	//绘制分数
void drawCompleteParticle(int line);

int RandomInt(int _min,int _max);		//获取一个随机int
int CheckValide(int curPosX,int curPosY,BOOL bCurTeris[4][4]);   //给定一个矩阵,查看是否合法
int selectDiffculty(HWND hWnd,int dif);
int selectLayOut(HWND hWnd,int layout);

//常量声明
const int BORDER_X = 10;
const int BORDER_Y = 10;
const int SCREEN_LEFT_X = 300 + BORDER_X;
const int SCREEN_Y = 600 + BORDER_Y;
const int SCREEN_RIGHT_X = 180+BORDER_X*2;
const int SCREEN_X = SCREEN_LEFT_X+SCREEN_RIGHT_X;
const BOOL state_teris[][4][4]=
{
	{{1,1,1,1},{0,0,0,0},{0,0,0,0},{0,0,0,0}},
	{{0,1,1,0},{0,1,1,0},{0,0,0,0},{0,0,0,0}},
	{{0,1,1,1},{0,0,0,1},{0,0,0,0},{0,0,0,0}},
	{{0,1,1,0},{0,0,1,1},{0,0,0,0},{0,0,0,0}},
	{{0,1,0,0},{1,1,1,0},{0,0,0,0},{0,0,0,0}},
	{{0,1,1,1},{0,1,0,0},{0,0,0,0},{0,0,0,0}},
	{{0,1,1,0},{1,1,0,0},{0,0,0,0},{0,0,0,0}}
};

//全局变量声明
bool g_hasBlocked[50][50];
RECT rc_left,rc_right,rc_right_top,rc_right_bottom,rc_main;
int g_speed = 300;
int t_speed = 300;
BOOL bCurTeris[4][4];
BOOL bNextCurTeris[4][4];
int curPosX,curPosY;
int rd_seed = 1995421;
int tPre=0,tCur;
int GAME_STATE = 0;
int GAME_SCORE=0;
int GAME_DIFF = 1;
int NUM_X = 10;
int NUM_Y = 20;
int BLOCK_SIZE = 30;

tetris.cpp:

// Tetris.cpp : 定义应用程序的入口点。
//

/*
记录于2016-5-29 星期日    由于闪屏过于显眼,采用双缓冲

*/

#include "stdafx.h"
#include "Tetris.h"
#include "windows.h"
#include <mmsystem.h>
#pragma comment(lib, "WINMM.LIB")
#define MAX_LOADSTRING 100

// 此代码模块中包含的函数的前向声明:
ATOM				MyRegisterClass(HINSTANCE hInstance);
BOOL				InitInstance(HINSTANCE, int);
LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK	About(HWND, UINT, WPARAM, LPARAM);

// 全局变量:
HINSTANCE hInst;								// 当前实例
TCHAR szTitle[MAX_LOADSTRING];					// 标题栏文本
TCHAR szWindowClass[MAX_LOADSTRING];			// 主窗口类名

int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
	init_game();
	UNREFERENCED_PARAMETER(hPrevInstance);
	UNREFERENCED_PARAMETER(lpCmdLine);

 	// TODO: 在此放置代码。
	MSG msg;
	HACCEL hAccelTable;

	// 初始化全局字符串
	LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
	LoadString(hInstance, IDC_TETRIS, szWindowClass, MAX_LOADSTRING);
	MyRegisterClass(hInstance);

	// 执行应用程序初始化:
	if (!InitInstance (hInstance, nCmdShow))
	{
		return FALSE;
	}

	hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_TETRIS));

	// 主消息循环:
	while (1)
	{
		if (PeekMessage(&msg,0,0,0,PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
			if (msg.message==WM_QUIT)
			{
				break;
			}
		}
		else
		{
			if ((GAME_STATE&2)!=0)
			{
				tCur = GetTickCount();
				if (tCur-tPre>g_speed)
				{

					int flag = CheckValide(curPosX,curPosY+1,bCurTeris);
					if (flag==1)
					{
						curPosY++;
						tPre = tCur;
						HWND hWnd = GetActiveWindow();
						InvalidateRect(hWnd,&rc_left,FALSE);
						InvalidateRect(hWnd,&rc_right_top,FALSE);
					}
					else if (flag==-2)
					{
						g_speed = t_speed;
						fillBlock();
						checkComplite();
						setRandomT();
						curPosX = (NUM_X-4)>>1;
						curPosY = 0;
						HWND hWnd = GetActiveWindow();
						InvalidateRect(hWnd,&rc_main,FALSE);
					}
					else if(flag==-3)
					{
						HWND hWnd = GetActiveWindow();
						if (MessageBox(hWnd,L"胜败乃兵家常事,菜鸡请重新来过",L":时光机",MB_YESNO)==IDYES)
						{
							init_game();
						}
						else
						{
							break;
						}
					}
				}
			}
		}
	}

	return (int) msg.wParam;
}

//
//  函数: MyRegisterClass()
//
//  目的: 注册窗口类。
//
//  注释:
//
//    仅当希望
//    此代码与添加到 Windows 95 中的“RegisterClassEx”
//    函数之前的 Win32 系统兼容时,才需要此函数及其用法。调用此函数十分重要,
//    这样应用程序就可以获得关联的
//    “格式正确的”小图标。
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
	WNDCLASSEX wcex;

	wcex.cbSize = sizeof(WNDCLASSEX);

	wcex.style			= CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc	= WndProc;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 0;
	wcex.hInstance		= hInstance;
	wcex.hIcon			= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_TETRIS));
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
	wcex.lpszMenuName	= MAKEINTRESOURCE(IDC_TETRIS);
	wcex.lpszClassName	= szWindowClass;
	wcex.hIconSm		= LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

	return RegisterClassEx(&wcex);
}

//
//   函数: InitInstance(HINSTANCE, int)
//
//   目的: 保存实例句柄并创建主窗口
//
//   注释:
//
//        在此函数中,我们在全局变量中保存实例句柄并
//        创建和显示主程序窗口。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   HWND hWnd;

   hInst = hInstance; // 将实例句柄存储在全局变量中

   hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}

//
//  函数: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  目的: 处理主窗口的消息。
//
//  WM_COMMAND	- 处理应用程序菜单
//  WM_PAINT	- 绘制主窗口
//  WM_DESTROY	- 发送退出消息并返回
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	int wmId, wmEvent;
	PAINTSTRUCT ps;
	HDC hdc;
	int nWinx,nWiny,nClientX,nClientY;
	int posX,posY;
	RECT rect;
	HMENU hSysmenu;
	switch (message)
	{
	case WM_CREATE:

		GetWindowRect(hWnd,&rect);
		nWinx = 530;
		nWiny = 680;
		posX = GetSystemMetrics(SM_CXSCREEN);
		posY = GetSystemMetrics(SM_CYSCREEN);
		posX = (posX - nWinx)>>1;
		posY = (posY - nWiny)>>1;
		GetClientRect(hWnd,&rect);
		nClientX = rect.right - rect.left;
		nClientY = rect.bottom - rect.top;

		MoveWindow(hWnd,posX,posY,530,680,TRUE);
		hSysmenu = GetSystemMenu(hWnd,false);
		AppendMenu(hSysmenu,MF_SEPARATOR,0,NULL);
		AppendMenu(hSysmenu,0,IDM_DIFF,L"难度选择");
		break;
	case WM_COMMAND:
		wmId    = LOWORD(wParam);
		wmEvent = HIWORD(wParam);
		// 分析菜单选择:
		switch (wmId)
		{
		case IDM_ABOUT:
			DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
			break;
		case IDM_EXIT:
			DestroyWindow(hWnd);
			break;
		case ID_dif1:
			selectDiffculty(hWnd,1);
			break;
		case ID_dif2:
			selectDiffculty(hWnd,2);
			break;
		case ID_dif3:
			selectDiffculty(hWnd,3);
			break;
		case ID_LAYOUT1:
			selectLayOut(hWnd,1);
			break;
		case ID_LAYOUT2:
			selectLayOut(hWnd,2);
			break;
		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
		}
		break;
	case WM_KEYDOWN:
		hdc = GetDC(hWnd);
		InvalidateRect(hWnd,NULL,false);
		switch(wParam)
		{
		case VK_LEFT:
			curPosX--;
			if(CheckValide(curPosX,curPosY,bCurTeris)!=1)
			{
				curPosX++;
			}
			break;
		case VK_RIGHT:
			curPosX++;
			if(CheckValide(curPosX,curPosY,bCurTeris)!=1)
			{
				curPosX--;
			}
			break;
		case VK_UP:
			RotateTeris(bCurTeris);
			break;
		case VK_DOWN:
			if (g_speed==t_speed)
				g_speed =10 ;
			else
				g_speed = t_speed;
			//outPutBoxInt(g_speed);
			break;
		case 'W':
			RotateTeris(bCurTeris);
			break;
		case 'A':
			curPosX--;
			if(CheckValide(curPosX,curPosY,bCurTeris)!=1)
			{
				curPosX++;
			}
			break;
		case 'D':
			curPosX++;
			if(CheckValide(curPosX,curPosY,bCurTeris)!=1)
			{
				curPosX--;
			}
			break;

		case 'S':
			if (g_speed==t_speed)
				g_speed =10 ;
			else
				g_speed = t_speed;
			//outPutBoxInt(g_speed);
			break;
		default:
			break;
		}

	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps);
		// TODO: 在此添加任意绘图代码...
		DrawBackGround(hdc);
		EndPaint(hWnd, &ps);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

// “关于”框的消息处理程序。
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	UNREFERENCED_PARAMETER(lParam);
	switch (message)
	{
	case WM_INITDIALOG:
		return (INT_PTR)TRUE;

	case WM_COMMAND:
		if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
		{
			EndDialog(hDlg, LOWORD(wParam));
			return (INT_PTR)TRUE;
		}
		break;
	}
	return (INT_PTR)FALSE;
}

void drawBlocked(HDC mdc)
{
	int i,j;

	HBRUSH hBrush = (HBRUSH)CreateSolidBrush(RGB(255,255,0));

	SelectObject(mdc,hBrush);

	for (i=0;i<NUM_Y;i++)
	{
		for (j=0;j<NUM_X;j++)
		{
			if (g_hasBlocked[i][j])
			{
				Rectangle(mdc,BORDER_X+j*BLOCK_SIZE,BORDER_Y+i*BLOCK_SIZE,
					BORDER_X+(j+1)*BLOCK_SIZE,BORDER_Y+(i+1)*BLOCK_SIZE
					);
			}
		}
	}
	DeleteObject(hBrush);
}

int CheckValide(int startX,int startY,BOOL bTemp[4][4])
{
	int i,j;
	for (i=3;i>=0;i--)
	{
		for (j=3;j>=0;j--)
		{
			if(bTemp[i][j])
			{
				if (j+startX<0||j+startX>=NUM_X)
				{
					return -1;
				}
				if (i+startY>=NUM_Y)
				{
					return -2;
				}
				if (g_hasBlocked[i+startY][j+startX])
				{
					//outPutBoxInt(j+startY);
					if (curPosY==0)
					{
						return -3;
					}
					return -2;
				}
			}
		}
	}
	//MessageBox(NULL,L"这里",L"as",MB_OK);
	//outPutBoxInt(curPosY);
	return 1;
}

void checkComplite()
{
	int i,j,k,count=0;
	for (i=0;i<NUM_Y;i++)
	{
		bool flag = true;
		for (j=0;j<NUM_X;j++)
		{
			if(!g_hasBlocked[i][j])
			{
				flag = false;
			}
		}
		if (flag)
		{
			count++;
			for (j=i;j>=1;j--)
			{
				for (k=0;k<NUM_X;k++)
				{
					g_hasBlocked[j][k] = g_hasBlocked[j-1][k];
				}

			}
			drawCompleteParticle(i);
			Sleep(300);

			PlaySound(_T("coin.wav"),NULL,SND_FILENAME|SND_ASYNC);
		}
	}
	GAME_SCORE += int(count*1.5);
}

VOID outPutBoxInt(int num)
{
	TCHAR szBuf[1024];
	LPCTSTR str = TEXT("%d");
	wsprintf(szBuf,str,num);
	MessageBox(NULL,szBuf,L"aasa",MB_OK);
}

VOID outPutBoxString(TCHAR str[1024])
{
	TCHAR szBuf[1024];
	LPCTSTR cstr = TEXT("%s");
	wsprintf(szBuf,cstr,str);
	MessageBox(NULL,szBuf,L"aasa",MB_OK);
}

void setRandomT()
{
	int rd_start = RandomInt(0,sizeof(state_teris)/sizeof(state_teris[0]));
	int rd_next = RandomInt(0,sizeof(state_teris)/sizeof(state_teris[0]));
	//outPutBoxInt(rd_start);
	//outPutBoxInt(rd_next);
	//outPutBoxInt(rd_start);
	if (GAME_STATE==0)
	{
		GAME_STATE = GAME_STATE | 0x0001;
		//outPutBoxInt(GAME_STATE);
		memcpy(bCurTeris,state_teris[rd_start],sizeof(state_teris[rd_start]));
		memcpy(bNextCurTeris,state_teris[rd_next],sizeof(state_teris[rd_next]));
	}
	else
	{
		memcpy(bCurTeris,bNextCurTeris,sizeof(bNextCurTeris));
		memcpy(bNextCurTeris,state_teris[rd_next],sizeof(state_teris[rd_next]));
	}

}
void init_game()
{
	GAME_SCORE = 0;
	setRandomT();
	curPosX = (NUM_X-4)>>1;
	curPosY = 0;

	memset(g_hasBlocked,0,sizeof(g_hasBlocked));
	rc_left.left = 0;
	rc_left.right = SCREEN_LEFT_X;
	rc_left.top = 0;
	rc_left.bottom = SCREEN_Y;

	rc_right.left = rc_left.right+BORDER_X;
	rc_right.right = 180+rc_right.left;
	rc_right.top = 0;
	rc_right.bottom = SCREEN_Y;

	rc_main.left = 0;
	rc_main.right = SCREEN_X;
	rc_main.top = 0;
	rc_main.bottom = SCREEN_Y;

	rc_right_top.left = rc_right.left;
	rc_right_top.top = rc_right.top;
	rc_right_top.right = rc_right.right;
	rc_right_top.bottom = (rc_right.bottom) / 2;

	rc_right_bottom.left = rc_right.left;
	rc_right_bottom.top = rc_right_top.bottom+BORDER_Y;
	rc_right_bottom.right = rc_right.right;
	rc_right_bottom.bottom = rc_right.bottom;

	g_speed = t_speed = 1000-GAME_DIFF*280;
}

void fillBlock()
{
	int i,j;
	for (i=0;i<4;i++)
	{
		for (j=0;j<4;j++)
		{
			if(bCurTeris[i][j])
			{
				g_hasBlocked[curPosY+i][curPosX+j] = 1;
			}
		}
	}
}

void RotateTeris(BOOL bTeris[4][4])
{
	BOOL bNewTeris[4][4];
	int x,y;
	for (x=0;x<4;x++)
	{
		for(y=0;y<4;y++)
		{
			bNewTeris[x][y] = bTeris[3-y][x];
			//逆时针:
			//bNewTeris[x][y] = bTeris[y][3-x];
		}
	}
	if (CheckValide(curPosX,curPosY,bNewTeris)==1)
	{
		memcpy(bTeris,bNewTeris,sizeof(bNewTeris));
	}

}

int RandomInt(int _min,int _max)
{
	srand((rd_seed++)%65532+GetTickCount());
	return _min+rand()%(_max-_min);
}

VOID DrawTeris(HDC mdc)
{

	int i,j;
	HPEN hPen = (HPEN)GetStockObject(BLACK_PEN);
	HBRUSH hBrush = (HBRUSH)GetStockObject(WHITE_BRUSH);
	SelectObject(mdc,hPen);
	SelectObject(mdc,hBrush);
	for (i=0;i<4;i++)
	{
		for (j=0;j<4;j++)
		{
			if(bCurTeris[i][j])
			{
				Rectangle(mdc,(j+curPosX)*BLOCK_SIZE+BORDER_X,(i+curPosY)*BLOCK_SIZE+BORDER_Y,(j+1+curPosX)*BLOCK_SIZE+BORDER_X,(i+1+curPosY)*BLOCK_SIZE+BORDER_Y);
			}
		}
	}
	drawBlocked(mdc);
	DeleteObject(hPen);
	DeleteObject(hBrush);
}

VOID DrawBackGround(HDC hdc)
{

	HBRUSH hBrush = (HBRUSH)GetStockObject(GRAY_BRUSH);
	HDC mdc = CreateCompatibleDC(hdc);
	HBITMAP hBitmap = CreateCompatibleBitmap(hdc,SCREEN_X,SCREEN_Y);

	SelectObject(mdc,hBrush);
	SelectObject(mdc,hBitmap);

	HBRUSH hBrush2 = (HBRUSH)GetStockObject(WHITE_BRUSH);
	FillRect(mdc,&rc_main,hBrush2);
	Rectangle(mdc,rc_left.left+BORDER_X,rc_left.top+BORDER_Y,rc_left.right,rc_left.bottom);
	Rectangle(mdc,rc_right.left+BORDER_X,rc_right.top+BORDER_Y,rc_right.right,rc_right.bottom);
	DrawTeris(mdc);
	drawNext(mdc);
	drawScore(mdc);
	::BitBlt(hdc,0,0,SCREEN_X,SCREEN_Y,mdc,0,0,SRCCOPY);
	DeleteObject(hBrush);
	DeleteDC(mdc);
	DeleteObject(hBitmap);
	DeleteObject(hBrush2);

	//	int x,y;
	// 	HPEN hPen = (HPEN)GetStockObject(NULL_PEN);
	// 	HBRUSH hBrush = (HBRUSH)GetStockObject(GRAY_BRUSH);
	// 	SelectObject(hdc,hPen);
	// 	SelectObject(hdc,hBrush);
	// 	for (x = 0;x<NUM_X;x++)
	// 	{
	// 		for(y=0;y<NUM_Y;y++)
	// 		{
	// 			Rectangle(hdc,BORDER_X+x*BLOCK_SIZE,BORDER_Y+y*BLOCK_SIZE,
	// 				BORDER_X+(x+1)*BLOCK_SIZE,
	// 				BORDER_Y+(y+1)*BLOCK_SIZE);
	// 		}
	// 	}
}

void drawNext(HDC hdc)
{
	int i,j;
	HBRUSH hBrush = (HBRUSH)CreateSolidBrush(RGB(0,188,0));
	SelectObject(hdc,hBrush);
	for (i=0;i<4;i++)
	{
		for (j=0;j<4;j++)
		{
			if(bNextCurTeris[i][j])
			{
				Rectangle(hdc,rc_right_top.left+BLOCK_SIZE*(j+1),rc_right_top.top+BLOCK_SIZE*(i+1),rc_right_top.left+BLOCK_SIZE*(j+2),rc_right_top.top+BLOCK_SIZE*(i+2));
			}
		}
	}
	HFONT hFont = CreateFont(30,0,0,0,FW_THIN,0,0,0,UNICODE,0,0,0,0,L"微软雅黑");
	SelectObject(hdc,hFont);
	SetBkMode(hdc,TRANSPARENT);
	SetBkColor(hdc,RGB(255,255,0));
	RECT rect;
	rect.left = rc_right_top.left+40;
	rect.top = rc_right_top.bottom -150;
	rect.right = rc_right_top.right;
	rect.bottom = rc_right_top.bottom;
	DrawTextW(hdc,TEXT("下一个"),_tcslen(TEXT("下一个")),&rect,0);
	DeleteObject(hFont);
	DeleteObject(hBrush);
}

void drawScore(HDC hdc)
{
	HFONT hFont = CreateFont(30,0,0,0,FW_THIN,0,0,0,UNICODE,0,0,0,0,L"微软雅黑");
	SelectObject(hdc,hFont);
	SetBkMode(hdc,TRANSPARENT);
	SetBkColor(hdc,RGB(255,255,0));
	RECT rect;
	rect.left = rc_right_bottom.left;
	rect.top = rc_right_bottom.top;
	rect.right = rc_right_bottom.right;
	rect.bottom = rc_right_bottom.bottom;
	TCHAR szBuf[30];
	LPCTSTR cstr = TEXT("当前难度:%d");
	wsprintf(szBuf,cstr,GAME_DIFF);
	DrawTextW(hdc,szBuf,_tcslen(szBuf),&rect,DT_CENTER | DT_VCENTER);

	RECT rect2;
	rect2.left = rc_right_bottom.left;
	rect2.top = rc_right_bottom.bottom/2+100;
	rect2.right = rc_right_bottom.right;
	rect2.bottom = rc_right_bottom.bottom;
	TCHAR szBuf2[30];
	LPCTSTR cstr2 = TEXT("得分:%d");
	wsprintf(szBuf2,cstr2,GAME_SCORE);
	//outPutBoxInt(sizeof(szBuf));
	DrawTextW(hdc,szBuf2,_tcslen(szBuf2),&rect2,DT_CENTER | DT_VCENTER);

	DeleteObject(hFont);
}

int selectDiffculty(HWND hWnd,int diff)
{
	TCHAR szBuf2[30];
	LPCTSTR cstr2 = TEXT("确认选择难度 %d 吗?");
	wsprintf(szBuf2,cstr2,diff);
	if (MessageBox(hWnd,szBuf2,L"难度选择",MB_YESNO)==IDYES)
	{
		GAME_DIFF = diff;
		InvalidateRect(hWnd,&rc_right_bottom,false);
		GAME_STATE |=2;
		init_game();
		return GAME_DIFF;
	}
	return -1;
}

int selectLayOut(HWND hWnd,int layout)
{
	NUM_X = 10*layout;
	NUM_Y = 20*layout;
	BLOCK_SIZE = 30/layout;
	GAME_STATE|=2;
	InvalidateRect(hWnd,&rc_right_bottom,false);
	init_game();
	return layout;
}

void drawCompleteParticle(int line)
{
	HWND hWnd = GetActiveWindow();
	HDC hdc = GetDC(hWnd);
	HBRUSH hBrush = (HBRUSH)GetStockObject(GRAY_BRUSH);
	HPEN hPen = (HPEN)CreatePen(PS_DOT,1,RGB(255,255,0));
	SelectObject(hdc,hBrush);
	SelectObject(hdc,hPen);
	Rectangle(hdc,BORDER_X,
		BORDER_Y+line*BLOCK_SIZE,
		BORDER_X+NUM_X*BLOCK_SIZE,
		BORDER_Y+BLOCK_SIZE*(1+line));
	DeleteObject(hBrush);
	DeleteObject(hPen);
}

于2016-5-29

时间: 2024-08-01 07:56:08

win32编程之俄罗斯方块的相关文章

Win32编程中如何处理控制台消息

这篇文章讨论如何处理所有的控制台消息. 第一步,首先要安装一个事件钩子,也就是说要建立一个回调函数.调用Win32 API,原型如下: BOOL SetConsoleCtrlHandler(PHANDLER_ROUTINE HandlerRoutine, // 回调函数BOOL Add // 表示添加还是删除): 参数HandlerRoutine是一个指向函数的指针,原型如下: BOOL WINAPI HandlerRoutine(DWORD dwCtrlType // 控制事件类型): 所有的

【WIN32编程】利用汇编写cs1.6辅助

这篇文章本来在2018.5.1号就写完发圈子去了,这两天跟朋友在网吧打单击才想起来,就顺便把内容发上去把 作者:admin-神风 用CE找到功能的地址 CS1.6下载地址:https://pan.baidu.com/s/1zaW6FmbZg50WV3EKX_IqHw 密码: srcs CE下载地址:https://pan.baidu.com/s/1_tVrikxFx2PAHhmlhWVfFQ 密码: dsn9 打开游戏,并利用CE打开游戏进程 这里我们以人物金钱和子弹为例,找到人物基址 ①查找金

Win32编程知识积累

Win32编程预知识 Windows sdk中有命令行工具,也有编译器和连接器.可以直接使用命令行编译链接C or C++编写的windows程序.而不必使用专业开发工具. Sdk(Software Development Kit)不支持硬件驱动开发. 绝大多数Windows APIs是由函数和com接口构成的,极少数是c++类(最典型的是GDI+, one of the 2-D graphics APIs) Windows api数据类型因为历史问题而有重复和冗余. ? 常用typedefs:

Win32编程API 基础篇 -- 1.入门指南 根据英文教程翻译

入门指南 本教程是关于什么的 本教程的目的是向你介绍使用win32 API编写程序的基础知识(和通用的写法).使用的语言是C,但大多数C++编译器也能成功编译,事实上,教程中的绝大多数内容都适用于任何可以连接API的语言,包括Java.Assembly和Visual Basic:我不会向你呈现任何跟这些语言相关的代码,这需要你在本教程的指导下自己去完成,有一些人在本API的基础上使用其他语言进行编程取得了相当的成功. 本教程不会教你C语言,也不会告诉你怎样去运行你特定的编译器(Borland C

Win32编程API 基础篇 -- 3.消息处理 根据英文教程翻译

消息处理 例子:窗口点击 好的,现在我们已经得到一个窗口了,但我们什么也做不了除了DefWindowProc()允许窗口大小被调整,最大最小化等...这不是很激动人心啊 在接下来的一小节中我将向你展示如何修改现有的程序,让它做一些新的事情,这样我就可以告诉你,“处理消息然后这样做...”,我会明白我的意思是什么并且在不需要看完完整的栗子的基础上完成它.所以不管怎样,集中注意力 OK,对初学者来说拿最近的一个窗口程序的代码,保证编译通过并且正常运行,然后你就可以在这份代码的基础上进行一些小修改,或

Win32编程API 基础篇 -- 4.消息循环 根据英文教程翻译

理解消息循环 为了编写任何即使是最简单的程序,了解windows程序的消息循环和整个消息发送结构是非常有必要的.既然我们已经尝试了一点消息处理的东西,我们应该对整个程序有更深入的理解,如果你没有理解消息是怎么发生的和它们运行的机制,那接下来的内容你会感到很蛋疼. 什么是消息? 一条消息是一个整数值,如果你查阅你的头文件(这是个好的查阅API的工作惯例)你会发现像下面的东西: 1 #define WM_INITDIALOG 0x0110 2 #define WM_COMMAND 0x0111 3

Win32编程笔记

我都决定了目前不再接触这些个浪费精力的API了,结果为了DirectX编程我特么又回来了.....微软你的东西真是坑人 以前用这玩意的时候需要什么就查,查完就忘了,这次记一记,以后再用也不至于忘的太离谱. Windows Notifications WM_CLOSE      告知程序你该被terminate了,但其余的什么都不会做,仅仅是一种提示.常用于关闭程序前提示保存.          出现时间:最早 WM_DESTROY  当程序的窗口被销毁后出现,表示程序正在被terminate,此

3D游戏引擎一 win32编程

Windows程序一般都等待用户进行一些操作,然后响应并采取行动. 一般来说,对win32的程序的操作都会转换为系统事件队列中的消息,如按键消息WM_KEYDOWN,WM_MOUSECLICK等传递键盘以及鼠标的操作消息.系统消息传递给程序的本地事件队列,然后在传递给WinProc()函数进行主窗口的消息处理,处理完消息后,程序转到WinMain()主函数中,而此时一般主函数依然在进行消息循环,于是又等待新的消息并执行. win32的程序都是有winmain开始,最简单的一个win32程序,从空

Win32编程API 基础篇 -- 5.使用资源

使用资源 你可能想参考教程结尾的附近,为了获得跟VC++和BC++资源相关的信息. 在我们讲得更加深入之前,我将大致讲解一下资源的主题,这样在每个小节中我就不必再去重讲一遍了.在这一小节中,你不需要编译任何东西,这里的代码只是个例子. 资源是以二进制的格式存储在你的可执行文件内部的预定义的数据,在资源脚本中我们创建资源,所谓的资源脚本就是有”.rc”扩展名的群文件,商业编译器通常有一个视觉资源编辑器老让你在不需要手动编辑的情况下创建资源,但很多时候手动这是唯一的创建资源的方法,如果你的编译器没有