WIN32 主程序
#include<Windows.h>
#include"Tetris.h"
LRESULT CALLBACK WndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam); // 回调函数
// WINAPI 调用约定
// 当前窗口句柄 HINSTANCE hInstance
// 前一个窗口句柄 HINSTANCE hPreInstance
// 指定命令行参数 LPTSTR lpCmdLine
// 窗口显示方式
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInstance, LPTSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc; // 初始化窗口类
wc.cbClsExtra = 0;
wc.cbSize = sizeof(WNDCLASSEX);
wc.cbWndExtra = 0;
wc.hbrBackground = (HBRUSH)COLOR_WINDOW; // 窗口背景颜色
wc.hCursor = NULL; // 鼠标光标
wc.hIcon = NULL; // 窗口大图标
wc.hIconSm = NULL; // 窗口的小图标
wc.hInstance = hInstance; // 窗口句柄
wc.lpfnWndProc = WndProc; // 回调函数地址
wc.lpszClassName = "Tetris"; // 窗口名字,给操作系统看的
wc.lpszMenuName = NULL; // 菜单名字
wc.style = CS_HREDRAW | CS_VREDRAW; // 窗口风格(垂直刷新和水平刷新)
// 12个成员
if (RegisterClassEx(&wc) == 0) // 注册窗口对象
return 0;
HWND hWnd = CreateWindowEx(WS_EX_TOPMOST,"Tetris", "俄罗斯方块",
WS_OVERLAPPEDWINDOW,100,100,500,650,NULL,
NULL, hInstance,NULL); // 创建窗口
if (hWnd == NULL)
return 0;
ShowWindow(hWnd, nCmdShow); // 显示窗口
MSG mSg; // 消息结构体
while (GetMessage(&mSg, NULL, 0, 0)) // 消息循环
{
TranslateMessage(&mSg); // 翻译消息
DispatchMessage(&mSg); // 分发消息
}
return 0;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam) // 回调函数
{
PAINTSTRUCT pt;
HDC hDC;
switch (nMsg)
{
case WM_CREATE: // 窗口创建初期只产生一次、
// 初始化数据
OnCreate();
break;
case WM_PAINT:
hDC = BeginPaint(hWnd,&pt); // 窗口可操作区域的标识
OnPaint(hDC); // 绘制界面
EndPaint(hWnd, &pt);
break;
case WM_TIMER:
OnTimer(hWnd); // 定时器相应函数
break;
case WM_KEYDOWN:
switch (wParam)
{
case VK_RETURN:
OnReturn(hWnd); // 回车响应函数
break;
case VK_LEFT:
OnLeft(hWnd); // 左键响应函数
break;
case VK_RIGHT:
OnRight(hWnd); // 右键响应函数
break;
case VK_UP:
OnChangeSquare(hWnd); // 上键响应函数
break;
case VK_DOWN: // 下键响应函数
OnDown(hWnd);
break;
}
break;
case WM_DESTROY:
KillTimer(hWnd, DEF_TIMER); // 关闭定时器
PostQuitMessage(0);
break;
}
return DefWindowProc(hWnd, nMsg, wParam, lParam); // 让系统自动处理一些消息
}
俄罗斯方块声明函数
#pragma once
#include<Windows.h>
#include<stdio.h>
#include<time.h>
#define DEF_TIMER 1234 // 定时器id
void OnPaint(HDC hDc); // 显示界面
void PaintSquare(HDC hDc); // 画方块
void CreateRandomSquare(); // 创建随机块
void CopySquareToBack(); // 随机快贴背景
void Change1To2(); // 方块落到最底部将1变为2
void ShowSquare2(HDC hMemDC); // 显示底部方块
void OnCreate(); // 创建背景随机块
void OnReturn(HWND hWnd); // 处理回车按键
void OnTimer(HWND hWnd); // 定时器响应函数
void OnLeft(HWND hWnd); // 处理左键
void OnRight(HWND hWnd); // 处理右键
void OnDown(HWND hWnd); // 处理下键
void OnChangeSquare(HWND hWnd); // 处理按上键方块变形
int CanSquareDown(); // 0代表方块不可以下落,1代表方块可以下落
int CanSquareDown2(); // 方块下落遇到障碍判断
int CanSquareLeft(); // 判断方块是否能左移
int CanSquareLeft2(); // 判断方块向左移动与存在方块碰撞
int CanSquareRight(); // 判断方块与右墙壁的碰撞
int CanSquareRight2(); // 检查方块与右方块的碰撞
int CanSquareChangeShape(); // 判断方块是否能变形
int CanLineSquareChange(); // 判断长条是否能变形
void SquareDown(); // 方块下落
void SquareLeft(); // 方块左移
void SquareRight(); // 方块右动
void ChangeSquare(); // 方块变形函数
void ChangeLineSquare(); // 长条变形
void DestroyOneLineSquare(); // 消除一行方块
void ShowScore(HDC hHemDC); // 显示分数
int CanGameOver(); // 游戏结束弹窗
具体函数实现
#include "Tetris.h"
char g_arrBackGround[20][10] = { 0 }; // 背景数组
char g_arrSquare[2][4] = { 0 }; // 方块类型的小数组
int g_nSquareID; // 方块的类型编号
int g_nLine = -1; // 方块包围盒的左上角行
int g_nList = -1; // 方块包围盒的左上角列
int g_nScore = 0; // 计分
void OnPaint(HDC hDc)
{
HDC hMemDC = CreateCompatibleDC(hDc); // 创建兼容性DC
HBITMAP hBitmapBack = CreateCompatibleBitmap(hDc, 500, 600); // 创建一张纸
SelectObject(hMemDC, hBitmapBack); // 窗口和纸关联在一起
PaintSquare(hMemDC); // 画方块
ShowSquare2(hMemDC); // 落到底部的方块,画颜色
ShowScore(hMemDC); // 界面显示分数
BitBlt(hDc, 0, 0, 500, 600, hMemDC, 0, 0, SRCCOPY); // 内存DC复制到窗口
DeleteObject(hBitmapBack); // 释放内存
DeleteDC(hMemDC);
}
void OnCreate()
{
srand((unsigned int)time(NULL)); // 当前系统时间作为随机数种子
CreateRandomSquare(); // 创建随机方块
CopySquareToBack(); // 将随机方块贴到背景
}
void PaintSquare(HDC hMemDC)
{
Rectangle(hMemDC, 0, 0, 300, 600); // 画矩形框
HGDIOBJ hOldBrush;
HGDIOBJ hNewBrush = CreateSolidBrush(RGB(63, 191, 49));
hOldBrush = SelectObject(hMemDC, hNewBrush);
for (int i = 0; i < 20; i++)
{
for (int j = 0; j < 10; j++)
{
if (g_arrBackGround[i][j] == 1)
{
Rectangle(hMemDC, j * 30, i * 30, (j + 1) * 30, (i + 1) * 30);
}
}
}
hNewBrush = SelectObject(hMemDC, hOldBrush);
DeleteObject(hNewBrush);
}
void CreateRandomSquare()
{
int n;
n = rand() % 7;
switch (n)
{
case 0:
g_arrSquare[0][0] = 1, g_arrSquare[0][1] = 1, g_arrSquare[0][2] = 0, g_arrSquare[0][3] = 0;
g_arrSquare[1][0] = 0, g_arrSquare[1][1] = 1, g_arrSquare[1][2] = 1, g_arrSquare[1][3] = 0;
g_nLine = 0;
g_nList = 3;
break;
case 1:
g_arrSquare[0][0] = 0, g_arrSquare[0][1] = 1, g_arrSquare[0][2] = 1, g_arrSquare[0][3] = 0;
g_arrSquare[1][0] = 1, g_arrSquare[1][1] = 1, g_arrSquare[1][2] = 0, g_arrSquare[1][3] = 0;
g_nLine = 0;
g_nList = 3;
break;
case 2:
g_arrSquare[0][0] = 1, g_arrSquare[0][1] = 0, g_arrSquare[0][2] = 0, g_arrSquare[0][3] = 0;
g_arrSquare[1][0] = 1, g_arrSquare[1][1] = 1, g_arrSquare[1][2] = 1, g_arrSquare[1][3] = 0;
g_nLine = 0;
g_nList = 3;
break;
case 3:
g_arrSquare[0][0] = 0, g_arrSquare[0][1] = 0, g_arrSquare[0][2] = 1, g_arrSquare[0][3] = 0;
g_arrSquare[1][0] = 1, g_arrSquare[1][1] = 1, g_arrSquare[1][2] = 1, g_arrSquare[1][3] = 0;
g_nLine = 0;
g_nList = 3;
break;
case 4:
g_arrSquare[0][0] = 0, g_arrSquare[0][1] = 1, g_arrSquare[0][2] = 0, g_arrSquare[0][3] = 0;
g_arrSquare[1][0] = 1, g_arrSquare[1][1] = 1, g_arrSquare[1][2] = 1, g_arrSquare[1][3] = 0;
g_nLine = 0;
g_nList = 3;
break;
case 5:
g_arrSquare[0][0] = 0, g_arrSquare[0][1] = 1, g_arrSquare[0][2] = 1, g_arrSquare[0][3] = 0;
g_arrSquare[1][0] = 0, g_arrSquare[1][1] = 1, g_arrSquare[1][2] = 1, g_arrSquare[1][3] = 0;
g_nLine = 0;
g_nList = 4;
break;
case 6:
g_arrSquare[0][0] = 1, g_arrSquare[0][1] = 1, g_arrSquare[0][2] = 1, g_arrSquare[0][3] = 1;
g_arrSquare[1][0] = 0, g_arrSquare[1][1] = 0, g_arrSquare[1][2] = 0, g_arrSquare[1][3] = 0;
g_nLine = 0;
g_nList = 4;
break;
}
g_nSquareID = n;
}
void CopySquareToBack()
{
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 4; j++)
{
g_arrBackGround[i][j+3] = g_arrSquare[i][j];
}
}
}
void OnReturn(HWND hWnd)
{
SetTimer(hWnd, DEF_TIMER, 400, NULL); // 直接调用定时器函数
}
void SquareDown()
{
for (int i = 19; i >= 0; i--)
{
for (int j = 0; j < 10; j++)
{
if (g_arrBackGround[i][j] == 1)
{
g_arrBackGround[i + 1][j] = g_arrBackGround[i][j];
g_arrBackGround[i][j] = 0;
}
}
}
}
void OnTimer(HWND hWnd)
{
HDC hDc = GetDC(hWnd);
if (CanSquareDown() == 1 && CanSquareDown2() == 1)
{
SquareDown(); // 如果方块能下落,方块下落
g_nLine++;
}
else
{
Change1To2(); // 当方块落到底部时,将1变为2
DestroyOneLineSquare(); // 消除方块
if (CanGameOver() == 0)
{
KillTimer(hWnd, DEF_TIMER);
return;
}
CanGameOver(); // 判断游戏结束
CreateRandomSquare(); // 如果方块落到底部,产生新的方块
CopySquareToBack();
}
OnPaint(hDc);
ReleaseDC(hWnd, hDc); // 释放
}
int CanSquareDown()
{
for (int i = 0; i < 10; i++)
{
if (g_arrBackGround[19][i] == 1)
{
return 0;
}
}
return 1;
}
void Change1To2()
{
for (int i = 0; i < 20; i++)
{
for (int j = 0; j < 10; j++)
{
if (g_arrBackGround[i][j] == 1)
{
g_arrBackGround[i][j] = 2;
}
}
}
}
void ShowSquare2(HDC hMemDC)
{
HGDIOBJ hOldBrush;
HGDIOBJ hNewBrush = CreateSolidBrush(RGB(233, 27, 182)); // 创建一个画刷
hOldBrush = SelectObject(hMemDC, hNewBrush);
for (int i = 0; i < 20; i++)
{
for (int j = 0; j < 10; j++)
{
if (g_arrBackGround[i][j] == 2)
{
Rectangle(hMemDC, j * 30, i * 30, (j + 1) * 30, (i + 1) * 30);
}
}
}
hNewBrush = SelectObject(hMemDC, hOldBrush);
DeleteObject(hNewBrush);
}
int CanSquareDown2()
{
for (int i = 19; i >=0; i--)
{
for (int j = 0; j < 10; j++)
{
if (g_arrBackGround[i][j] == 1 && g_arrBackGround[i+1][j] == 2)
{
return 0;
}
}
}
return 1;
}
void OnLeft(HWND hWnd)
{
if (CanSquareLeft() == 1 && CanSquareLeft2()==1)
{
HDC hDc = GetDC(hWnd);
SquareLeft(); // 方块向左移
g_nList--;
OnPaint(hDc);
ReleaseDC(hWnd, hDc);
}
}
void SquareLeft()
{
for (int i = 0; i < 20; i++)
{
for (int j = 0; j < 10; j++)
{
if (g_arrBackGround[i][j] == 1)
{
g_arrBackGround[i][j-1] = g_arrBackGround[i][j];
g_arrBackGround[i][j] = 0;
}
}
}
}
int CanSquareLeft()
{
for (int i = 0; i < 20; i++)
{
if (1 == g_arrBackGround[i][0])
{
return 0;
}
}
return 1;
}
int CanSquareLeft2()
{
for (int i = 0; i < 20; i++)
{
for (int j = 0; j < 10; j++)
{
if (g_arrBackGround[i][j] == 1 && g_arrBackGround[i][j - 1] == 2)
return 0;
}
}
return 1;
}
void OnRight(HWND hWnd)
{
if (CanSquareRight() == 1 && CanSquareRight2()==1)
{
HDC hDc = GetDC(hWnd);
SquareRight();
g_nList++;
OnPaint(hDc);
ReleaseDC(hWnd, hDc);
}
}
void SquareRight()
{
for (int i = 0; i < 20; i++)
{
for (int j = 9; j >= 0; j--)
{
if (g_arrBackGround[i][j] == 1)
{
g_arrBackGround[i][j + 1] = g_arrBackGround[i][j];
g_arrBackGround[i][j] = 0;
}
}
}
}
int CanSquareRight()
{
for (int i = 0; i < 20; i++)
{
if (g_arrBackGround[i][9] == 1)
{
return 0;
}
}
return 1;
}
int CanSquareRight2()
{
for (int i = 0; i < 20; i++)
{
for (int j = 9; j >= 0; j--)
{
if (g_arrBackGround[i][j] == 1 && g_arrBackGround[i][j+1]==2)
{
return 0;
}
}
}
return 1;
}
void OnDown(HWND hWnd)
{
OnTimer(hWnd);
}
void OnChangeSquare(HWND hWnd)
{
HDC hDc = GetDC(hWnd);
switch (g_nSquareID)
{
case 0:
case 1:
case 2:
case 3:
case 4:
if (CanSquareChangeShape() == 1)
ChangeSquare();
else
return;
break;
case 5:
return; // 正方形不变形
case 6:
if (CanLineSquareChange() == 1)
ChangeLineSquare();
break;
}
OnPaint(hDc);
ReleaseDC(hWnd, hDc);
}
void ChangeSquare()
{
char arrSquare[3][3] = { 0 };
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++) // 背景块复制出来
{
arrSquare[i][j] = g_arrBackGround[g_nLine + i][g_nList + j];
}
}
int nTemp;
for (int i = 0; i < 3; i++)
{
nTemp = 2;
for (int j = 0; j < 3; j++)
{
g_arrBackGround[g_nLine + i][g_nList + j] = arrSquare[nTemp][i];
nTemp--;
}
}
}
int CanSquareChangeShape()
{
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
if (g_arrBackGround[g_nLine + i][g_nList + j] == 2)
return 0;
}
}
if (g_nList < 0)
g_nList = 0;
else if (g_nList > 7)
g_nList = 7;
return 1;
}
void ChangeLineSquare()
{
if (g_arrBackGround[g_nLine][g_nList - 1] == 1)
{
// 清零
g_arrBackGround[g_nLine][g_nList - 1] = 0;
g_arrBackGround[g_nLine][g_nList + 1] = 0;
g_arrBackGround[g_nLine][g_nList + 2] = 0;
if (g_arrBackGround[g_nLine + 1][g_nList] == 2)
{
g_arrBackGround[g_nLine - 3][g_nList] = 1;
g_arrBackGround[g_nLine - 2][g_nList] = 1;
g_arrBackGround[g_nLine - 1][g_nList] = 1;
//g_nLine -= 2;
}
else if(g_arrBackGround[g_nLine + 2][g_nList] == 2)
{
g_arrBackGround[g_nLine + 1][g_nList] = 1;
g_arrBackGround[g_nLine - 1][g_nList] = 1;
g_arrBackGround[g_nLine - 2][g_nList] = 1;
//g_nLine--;
}
else
{
// 元素赋值
g_arrBackGround[g_nLine - 1][g_nList] = 1;
g_arrBackGround[g_nLine + 1][g_nList] = 1;
g_arrBackGround[g_nLine + 2][g_nList] = 1;
}
}
else
{
// 清零
g_arrBackGround[g_nLine - 1][g_nList] = 0;
g_arrBackGround[g_nLine + 1][g_nList] = 0;
g_arrBackGround[g_nLine + 2][g_nList] = 0;
if (g_arrBackGround[g_nLine][g_nList + 1] == 2 || g_nList==9)
{
g_arrBackGround[g_nLine][g_nList - 1] = 1;
g_arrBackGround[g_nLine][g_nList - 2] = 1;
g_arrBackGround[g_nLine][g_nList - 3] = 1;
g_nList -= 2;
}
else if (g_arrBackGround[g_nLine][g_nList + 2] == 2|| g_nList ==8)
{
g_arrBackGround[g_nLine][g_nList + 1] = 1;
g_arrBackGround[g_nLine][g_nList - 1] = 1;
g_arrBackGround[g_nLine][g_nList - 2] = 1;
g_nList -= 2;
}
else if (g_arrBackGround[g_nLine][g_nList - 1] == 2 || g_nList == 0)
{
g_arrBackGround[g_nLine][g_nList + 1] = 1;
g_arrBackGround[g_nLine][g_nList + 2] = 1;
g_arrBackGround[g_nLine][g_nList + 3] = 1;
g_nList++;
}
else
{
g_arrBackGround[g_nLine][g_nList - 1] = 1;
g_arrBackGround[g_nLine][g_nList + 1] = 1;
g_arrBackGround[g_nLine][g_nList + 2] = 1;
}
}
}
int CanLineSquareChange()
{
int i, j;
for (i = 1; i < 4; i++)
{
if (g_arrBackGround[g_nLine][g_nList + i] == 2
|| g_nList+i>9)
{
break;
}
}
for (j = 1; j < 4; j++)
{
if (g_arrBackGround[g_nLine][g_nList - j] == 2 || g_nList - j < 0)
{
break;
}
}
if (i - 1 + j - 1 < 3)
return 0;
return 1;
}
void DestroyOneLineSquare()
{
int nSum = 0;
for (int i = 19; i >= 0; i--)
{
for (int j = 0; j < 10; j++)
{
nSum += g_arrBackGround[i][j];
}
if (nSum == 20)
{
g_nScore += 10;
for (int k = i - 1; k >= 0; k--)
{
for (int l = 0; l < 10; l++)
{
g_arrBackGround[k + 1][l] = g_arrBackGround[k][l];
}
}
i = 20;
}
nSum = 0;
}
}
void ShowScore(HDC hMemDC)
{
char strScore[10] = { 0 }; // 分数字符串
Rectangle(hMemDC, 300, 0, 500, 600);
sprintf_s(strScore, "%d", g_nScore, strlen(strScore));
TextOut(hMemDC, 400, 100, strScore, strlen(strScore));
}
int CanGameOver()
{
for (int i = 0; i < 10; i++)
{
if (g_arrBackGround[0][i] == 2)
{
MessageBox(NULL,"GameOver","提示",MB_OK); // 游戏结束
return 0;
}
}
return 1;
}