博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
windows下实现win32俄罗斯方块练手,编程的几点心得
阅读量:6807 次
发布时间:2019-06-26

本文共 11921 字,大约阅读时间需要 39 分钟。

编程珠玑2阅读笔记:

1.使用c语言性能监视器,完成对代码的调优工作
2.关联数组:
 拓扑排序算法,可以用于当存在遮挡的时候决定三维场景的绘制顺序。
3.小型算法中的测试与调试工具
脚手架程序:《人月神话》一个软件产品中应该有一半的代码都是脚手架。
类似,小型的代码库
4.自描述数据
每个程序员都知道破解神秘数据的挫折与艰辛。
5.劈开戈尔迪之结
什么是用户的真正需求:
一个运筹学者接到任务,设计末座大楼的电梯调度策略,使乘客等待的时间最短,在走访了这座大楼之后,他认识到雇主真正想要解决的问题是,尽量减少乘客的不适( 乘客不喜欢等电梯)。他这样解决问题:在每部电梯附近装上几面镜子。乘客在等电梯时候,可以自我欣赏一下,对电梯速度的抱怨大幅减少了。他发现了用户的真正需求
7.粗略估算
程序员3大美德:对数值敏感,实验的欲望,良好的数学功底

在来说这个俄罗斯方块,其实主要是2个大的部分:

1.界面绘制(游戏区,信息区,刷新重绘工作)

游戏区方块的绘制,其实都是数组来记录

2.游戏逻辑(上下左右,变形)

其实就是对数组的旋转

主要代码,才六百行:

// Russian_cube.cpp : 定义应用程序的入口点。////////#include "stdafx.h"#include "Russian_cube.h"#define MAX_LOADSTRING 100//Tetris#define BOUND_SIZE 10#define TETRIS_SIZE 30#define GAME_X 10#define GAME_Y 20#define INFO_X 6#define INFO_Y GAME_Y//定时器#define  MY_TIMEER 1#define  DEFAULT_INTERVAL 500 //默认每0.5秒下降一格//定义俄罗斯方块的形状BOOL g_astTetris[][4][4] = {	{
{1,1,0,1},{0,0,0,0},{0,0,0,0},{0,0,0,0}}, {
{1,1,0,0},{0,0,1,1},{0,0,0,0},{0,0,0,0}}, {
{1,1,0,0},{1,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}}, {
{0,1,0,0},{1,1,1,0},{0,0,0,0},{0,0,0,0}}, {
{1,1,1,1},{0,0,0,0},{0,0,0,0},{0,0,0,0}}};#define TETRIS_CNT (sizeof(g_astTetris)/sizeof(g_astTetris[0]))//当前方块的形状BOOL g_CurTetris[4][4];BOOL g_NextTetris[4][4];BOOL g_stGame[GAME_X][GAME_Y];//记录已经落下来的方块//记录方块左上角的坐标UINT TetrisX;UINT TetrixY;UINT g_uiInterval;UINT g_uiScore;UINT g_uiMySeed = 0xffff;// 全局变量:HINSTANCE hInst; // 当前实例TCHAR szTitle[MAX_LOADSTRING]; // 标题栏文本TCHAR szWindowClass[MAX_LOADSTRING]; // 主窗口类名// 此代码模块中包含的函数的前向声明:ATOM MyRegisterClass(HINSTANCE hInstance);BOOL InitInstance(HINSTANCE, int);LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow){ UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); // TODO: 在此放置代码。 MSG msg; HACCEL hAccelTable; // 初始化全局字符串 LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); LoadString(hInstance, IDC_RUSSIAN_CUBE, szWindowClass, MAX_LOADSTRING); MyRegisterClass(hInstance); // 执行应用程序初始化: if (!InitInstance (hInstance, nCmdShow)) { return FALSE; } hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_RUSSIAN_CUBE)); // 主消息循环: while (GetMessage(&msg, NULL, 0, 0)) { if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } 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_RUSSIAN_CUBE)); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = MAKEINTRESOURCE(IDC_RUSSIAN_CUBE); 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_MINIMIZEBOX | WS_SYSMENU, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); if (!hWnd) { return FALSE; } ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE;}int GetRandNum(int iMin,int iMax){ //取随机数 srand(GetTickCount() + g_uiMySeed-- ); return iMin + rand()%(iMax -iMin);}VOID DrawBackGround(HDC hdc){ int x, y; HPEN hPen = (HPEN)GetStockObject(NULL_PEN); HBRUSH hBrush = (HBRUSH)GetStockObject(GRAY_BRUSH); //(HBRUSH)CreateSolidBrush() HBRUSH hBrush_luo = (HBRUSH)GetStockObject(BLACK_BRUSH); Rectangle(hdc,BOUND_SIZE,BOUND_SIZE,BOUND_SIZE + GAME_X*TETRIS_SIZE ,BOUND_SIZE + GAME_Y * TETRIS_SIZE); SelectObject(hdc,hPen); for (x = 0; x < GAME_X; x++) { for (y = 0 ;y < GAME_Y; y++) { if (g_stGame[x][y]) { SelectObject(hdc,hBrush_luo); } else { SelectObject(hdc,hBrush); } Rectangle(hdc,BOUND_SIZE + x*TETRIS_SIZE, BOUND_SIZE + y * TETRIS_SIZE, BOUND_SIZE + (x + 1)*TETRIS_SIZE, BOUND_SIZE + (y + 1) * TETRIS_SIZE); } }}//信息区 的绘制VOID DrawInfo(HDC hdc){ int x,y; int nStartX,nStartY; RECT rect; TCHAR szBuf[100];//得分的字符串 HPEN hPen = (HPEN)GetStockObject(BLACK_PEN); HBRUSH hBrush = (HBRUSH)GetStockObject(NULL_BRUSH); HBRUSH hBrush_have = (HBRUSH)GetStockObject(GRAY_BRUSH); SelectObject(hdc,hPen); SelectObject(hdc,hBrush); Rectangle(hdc,BOUND_SIZE*2 + GAME_X * TETRIS_SIZE, BOUND_SIZE,BOUND_SIZE *2 + (GAME_X + INFO_X)*TETRIS_SIZE, BOUND_SIZE + INFO_Y * TETRIS_SIZE); for (x = 0; x < 4; x++) { for (y = 0 ;y < 4 ;y++) { nStartX = BOUND_SIZE *2 + GAME_X*TETRIS_SIZE + (y +1)*TETRIS_SIZE; nStartY = BOUND_SIZE + (x +1)*TETRIS_SIZE; if (g_NextTetris[x][y]) { SelectObject(hdc,hBrush); } else { SelectObject(hdc,hBrush_have); } Rectangle(hdc,nStartX,nStartY,nStartX+TETRIS_SIZE,nStartY+TETRIS_SIZE); } } nStartX = BOUND_SIZE *2 + GAME_X*TETRIS_SIZE; nStartY = BOUND_SIZE ; rect.left = nStartX + TETRIS_SIZE; rect.right = nStartX + TETRIS_SIZE * (INFO_X -1); rect.top = nStartY + TETRIS_SIZE *6; rect.bottom = nStartY + TETRIS_SIZE *7; wsprintf(szBuf,L"Score: %d",g_uiScore = 0); DrawText(hdc,szBuf,wcslen(szBuf),&rect,DT_CENTER);}//绘制区方块,起始坐标和需要绘制的方块形状VOID DrawTetris(HDC hdc, int nStartX,int nStartY,BOOL bTetris[4][4]){ int i,j; HPEN hPen = (HPEN)GetStockObject(BLACK_PEN); HBRUSH hBrush = (HBRUSH)GetStockObject(WHITE_BRUSH); SelectObject(hdc,hPen); SelectObject(hdc,hBrush); for (i = 0;i < 4; i++) { for (j = 0;j < 4;j++) { //j 是x方向的坐标偏移 if (bTetris[i][j]) { Rectangle(hdc,BOUND_SIZE +(nStartX + j) * TETRIS_SIZE, BOUND_SIZE + (nStartY + i)* TETRIS_SIZE, BOUND_SIZE +(nStartX + j + 1) * TETRIS_SIZE, BOUND_SIZE + (nStartY + i + 1)* TETRIS_SIZE); } } }}//旋转方块, 并且靠左上角VOID RotateTetris(BOOL bTetris[4][4]){ BOOL bNewTetris[4][4] = {};//初始化置零 int x, y; int xPos,yPos; BOOL bFlag;//靠近左上角 //从上往下,从左往右,顺时针旋转 //靠上 for (x = 0,xPos = 0 ;x < 4 ; x++) { bFlag = FALSE; for (y = 0 ;y < 4 ;y++) { bNewTetris[xPos][y] = bTetris[3 - y][x]; //逆时针旋转 //bNewTetris[x][y] = bTetris[y][3 - x]; if (bNewTetris[xPos][y]) { bFlag = TRUE;//这一行有数据 } } if (bFlag) { xPos++; } } memset(bTetris,0,sizeof(bNewTetris)); //靠左 for (y = 0, yPos = 0;y < 4 ;y++) { bFlag = FALSE; for (x = 0;x < 4; x++) { bTetris[x][yPos] = bNewTetris[x][y]; if (bTetris[x][yPos]) { bFlag = TRUE; } } if (bFlag) { yPos++; } } //memcpy(bTetris,bNewTetris,sizeof(bNewTetris)); return;}BOOL CheckTetris(int nStartX,int nStartY,BOOL bTetris[4][4],BOOL bGame[GAME_X][GAME_Y]){ int x,y; if (nStartX < 0) {//碰到左墙 return FALSE; } for (x = 0;x < 4;x++) { for (y = 0;y < 4;y++) { if (bTetris[x][y]) { //碰右墙 if (nStartX +y >=GAME_X) { return FALSE; } //碰下墙 if (nStartY + x >=GAME_Y) { return FALSE; } //碰到已有的方块 if (bGame[nStartX +y][nStartY + x]) { return FALSE; } } } } return TRUE;}//落地的方块合并,并且满足消除一行VOID RefreshTetris(int nStartX,int nStartY,BOOL bTetris[4][4], BOOL bGame[GAME_X][GAME_Y]){ BOOL bFlag = FALSE; int x,y; int newX,newY;//主要用来记录 int iFulllie = 0; //校区满行的格子记录行数,用于积分 for (x = 0; x < 4;x ++) { for (y = 0 ;y < 4; y++) { if (bTetris[x][y]) { bGame[nStartX + y][nStartY +x] = TRUE; } } } for (y = GAME_Y,newY = GAME_Y; y >= 0; y--) { bFlag= FALSE; for (x = 0;x < GAME_X;x++) { bGame[x][newY] = bGame[x][y]; if (!bGame[x][y])//这一行不满格 { bFlag = TRUE; } } if (bFlag) { newY--; } else { //满格的话,用上一行替换这一行 iFulllie++; } } if (iFulllie) { g_uiScore -= iFulllie *1; } //合并以后生成新的方块,并刷新位置 memcpy(g_CurTetris,g_NextTetris,sizeof(g_CurTetris)); memcpy(g_NextTetris,g_astTetris[ GetRandNum(0,TETRIS_CNT)],sizeof(g_NextTetris)); TetrisX = (GAME_X - 4)/2; TetrixY = 0;}//初始化游戏,就是方块最先初始化的位置VOID InitGame(){ int iTmp; TetrisX = (GAME_X - 4 )/2 ; //居中 TetrixY = 0; g_uiScore = 0; g_uiInterval = DEFAULT_INTERVAL; iTmp = GetRandNum(0,TETRIS_CNT); memcpy(g_CurTetris,g_astTetris[iTmp],sizeof(g_CurTetris)); iTmp = GetRandNum(0,TETRIS_CNT); memcpy(g_NextTetris,g_astTetris[iTmp],sizeof(g_NextTetris)); memset(g_stGame,0,sizeof(g_stGame));}//// 函数: 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; RECT rect; BOOL bTmpTetris[4][4] = {}; switch (message) { case WM_CREATE: //获取窗口大小 GetWindowRect(hWnd,&rect); nWinX = rect.right - rect.left; nWinY = rect.bottom - rect.top; //获取客户区大小 GetClientRect(hWnd,&rect); nClientX = rect.right - rect.left; nClientY = rect.bottom - rect.top; MoveWindow(hWnd,0,0,3 * BOUND_SIZE + (GAME_X + INFO_X)* TETRIS_SIZE + (nWinX - nClientX), 2 * BOUND_SIZE + GAME_Y*TETRIS_SIZE + (nWinY - nClientY),true); InitGame(); SetTimer(hWnd,MY_TIMEER,g_uiInterval,NULL); break; case WM_TIMER: //定时器中方块下降 if (CheckTetris(TetrisX,TetrixY + 1,g_CurTetris,g_stGame)) { TetrixY++; } else { if (TetrixY == 0) { MessageBox(NULL,L"不行了",L"shit!",MB_OK); KillTimer(hWnd,MY_TIMEER); } RefreshTetris(TetrisX,TetrixY,g_CurTetris,g_stGame); } InvalidateRect(hWnd,NULL,TRUE); break; case WM_LBUTTONDOWN: RotateTetris(g_CurTetris); InvalidateRect(hWnd,NULL,TRUE); break; case WM_KEYDOWN: switch(wParam) { case VK_LEFT://左方向键 if (CheckTetris(TetrisX -1,TetrixY,g_CurTetris,g_stGame)) {//判断一下当前方块没有靠墙就 TetrisX--; InvalidateRect(hWnd,NULL,TRUE); } else { MessageBeep(0); } break; case VK_RIGHT: if (CheckTetris(TetrisX +1,TetrixY,g_CurTetris,g_stGame)) {//判断一下当前方块没有靠墙就 TetrisX++; InvalidateRect(hWnd,NULL,TRUE); } else { MessageBeep(0); } break; case VK_UP://变形,但是要判断变形成功或者失败 memcpy(bTmpTetris,g_CurTetris,sizeof(bTmpTetris)); RotateTetris((bTmpTetris)); if (CheckTetris(TetrisX,TetrixY,bTmpTetris,g_stGame)) { //成功后,再把旋转后的copy回来 memcpy(g_CurTetris,bTmpTetris,sizeof(bTmpTetris)); InvalidateRect(hWnd,NULL,TRUE); } break; case VK_DOWN: while (CheckTetris(TetrisX,TetrixY + 1,g_CurTetris,g_stGame)) { TetrixY++; } RefreshTetris(TetrisX,TetrixY,g_CurTetris,g_stGame); InvalidateRect(hWnd,NULL,TRUE); break; default: break; } 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; default: return DefWindowProc(hWnd, message, wParam, lParam); } break; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); // TODO: 在此添加任意绘图代码... DrawBackGround(hdc); DrawInfo(hdc); DrawTetris(hdc,TetrisX,TetrixY,g_CurTetris); EndPaint(hWnd, &ps); break; case WM_DESTROY: KillTimer(hWnd,MY_TIMEER); 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;}

代码参考:

主要是听了这个课程,这个公开课做点小项目,贪吃蛇,网络啊什么的,都是代码挺好的,作为一个熟悉其他领域的小项目非常适合上手:

windows下的win32编程要学的东西还比较多,下面给出一个简单的知识点:

你可能感兴趣的文章
Struts2升级版本至2.5.10,高危漏洞又来了
查看>>
OpenCV 使用 FLANN 库实现特征匹配
查看>>
SOA webservice
查看>>
用Dart搭建HTTP服务器(2)
查看>>
elasticsearch数据长期保存的方案
查看>>
GIS 资源网站
查看>>
redis - 00 在centos安装
查看>>
说说ejabberd离线消息踩过的坑
查看>>
mysql-mmm+amoeba+keepalived实现mysql高可用和读写分离(二)
查看>>
Java的IO演进
查看>>
[xmind] ASP.NET 设计模式 - UX 用户体验
查看>>
Productivity Power Tools(Visual Studio 扩展) 最新亮点
查看>>
VMware View 5.0 策略列表
查看>>
svn版本内容信息存放路径
查看>>
历届奥斯卡获奖影片(1971-2014年)
查看>>
企业园区全面安防面临的问题及解决之道
查看>>
Head First Design Pattern: 策略模式
查看>>
我的友情链接
查看>>
摩游世纪CEO宋啸飞:Html5增长趋势已可见
查看>>
react学习笔记10:显示隐藏效果和tab切换效果
查看>>