⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 toybricks.cpp

📁 简单的俄罗斯方块游戏
💻 CPP
字号:
// ToyBricks.cpp : Defines the entry point for the application.
//

#include "stdafx.h"


/*******************************************************/

/* 文 件 名: ToyBricks.c
 * 完成时间: 2001年9月
 * 完成地点: 华东地质学院综合楼507机房
 * 开发模式: SDK程序
 * 开发环境: MS VC++ 6.0
 * 作    者: 毛建忠
 * 工作单位: 中国建设银行三水市(广东省)支行
 * E - Mail: Mao_jzh@163.com       
*/

/* 备注:
 *     这是一个简单的俄罗斯方块游戏程序,写程序时没有注释,
 * 这是我写程序时的一个坏习惯。毕业有半年了,也就半年没有写
 * 过程序,周末闲着没事,捡起那些旧程序看看,顺便加上一些注
 * 释。很怀念在学校写程序的那段日子,很怀念507。
*/

/*******************************************************/

#include <windows.h>
#include <time.h>
#include <stdlib.h>

#define CELL	15             // 【方格】的边长(pix)  
#define W		22             // 游戏区宽(22个【方格】边长)
#define H		30             // 游戏区高(30个【方格】边长)
#define MS_NEWBLOCK	WM_USER+1  // 消息ID,产生新的【方块】
#define MS_DRAW		WM_USER+2 

LRESULT CALLBACK WndProc ( HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain ( HINSTANCE	hInstance,	
					 HINSTANCE	hPrevInstance, 
					 PSTR		szCmdLine, 
					 int		iCmdShow)
{
	static char AppName[]="ToyBrick";
	HWND		hwnd;
	MSG			msg;
	WNDCLASSEX	wndclass;
	int			iScreenWide;

	wndclass.cbSize			= sizeof(wndclass);
	wndclass.style			= CS_HREDRAW|CS_VREDRAW;
	wndclass.lpfnWndProc	= WndProc;
	wndclass.cbClsExtra		= 0;
	wndclass.cbWndExtra		= 0;
	wndclass.hInstance		= hInstance;
	wndclass.hIcon			= LoadIcon (NULL, IDI_APPLICATION);
	wndclass.hCursor		= LoadCursor (NULL,IDC_ARROW);
	wndclass.hbrBackground	= (HBRUSH)GetStockObject (BLACK_BRUSH);
	wndclass.lpszMenuName	= NULL;
	wndclass.lpszClassName	= AppName;
	wndclass.hIconSm		= LoadIcon (NULL, IDI_APPLICATION);

	if(!RegisterClassEx (&wndclass)) return FALSE;

	// 获取显示器分辨率的X值iScreenWide,将程序窗口置于屏幕中央
	iScreenWide=GetSystemMetrics (SM_CXFULLSCREEN);

	hwnd =CreateWindow (AppName,
		"俄罗斯方块",
		WS_MINIMIZEBOX|WS_SYSMENU ,
		iScreenWide/2-W*CELL/2, CELL,
		(W+1)*CELL-8, H*CELL,
		NULL, NULL,
		hInstance,
		NULL );
	if(!hwnd) return FALSE;

	ShowWindow (hwnd,iCmdShow);
	UpdateWindow (hwnd);
	MessageBox(hwnd,"开始游戏","开始",MB_OK);
	SendMessage(hwnd,MS_NEWBLOCK,0,0);
	SetTimer (hwnd, 1, 550,NULL);

	while (GetMessage (&msg, NULL, 0, 0))
	{
		TranslateMessage (&msg);
		DispatchMessage (&msg);
	}

	return msg.wParam;
}

// 函数DrawRact: 画【正方形】
// 参数: 设备环境句柄和【正方形】的四角坐标
void DrawRect (HDC hdc, int l, int t, int r, int b)
{
	MoveToEx (hdc, l, t, NULL);
	LineTo (hdc, r, t);
	LineTo (hdc, r, b);
	LineTo (hdc, l, b);
	LineTo (hdc, l,t);
}

// 函数DrawCell: 画【方格】
// 参数: 设备环境句柄和【方格】的四角坐标
// 每个方格由内外两个【正方形】(DrawCell)画成,使其有立体感
void DrawCell (HDC hdc, int l, int t, int r, int b)
{
	DrawRect (hdc,l+1, t+1, r-1, b-1);
	DrawRect (hdc,l+3, t+3, r-3, b-3);
}

// 函数DrawBlock: 画【方块】
// 参数: 设备环境句柄和【方块】中四个【方格】在游戏区域中的位置
// 每个【方块】由四个【方格】组成7种不同的形状
void DrawBlock (HDC hdc, int block[4][2])
{
	int i;
	HPEN hpen;
	hpen =CreatePen (PS_SOLID,1,RGB(255,255,255));
	SelectObject (hdc,hpen);
	for(i=0; i<4; i++)
		DrawCell (hdc, (block[i][0]-1)*CELL, (block[i][1]-1)*CELL, //....
				  block[i][0]*CELL, block[i][1]*CELL);
	DeleteObject (hpen);
}

// 函数Cover: 清除原来位置的【方块】
// 参数: 设备环境句柄和待清除的【方块】
// 清除【方块】即在该【方块】的每个【方块】处画一个正方形的黑块
void Cover (HDC hdc, int org[4][2])
{
	int i;
	SelectObject (hdc, (HBRUSH)GetStockObject (BLACK_BRUSH));
	for(i=0; i<4; i++)
		Rectangle ( hdc, (org[i][0]-1)*CELL, (org[i][1]-1)*CELL, //.....
					org[i][0]*CELL, org[i][1]*CELL);
}

// 窗口过程函数WndProc
LRESULT CALLBACK WndProc ( HWND		hwnd, 
						   UINT		iMsg, 
						   WPARAM	wParam, 
						   LPARAM	lParam )
{
	int			i,j,k,lines,r;
	static int	top, sel, flag;
	static int	cells[W+2][H];        // 控制游戏的【方格矩阵】
	static int	org[4][2], block[4][2];       // 【方块】
	HDC			hdc;
	HPEN		hpen;
	PAINTSTRUCT ps;

	switch (iMsg)
	{
	case WM_CREATE:
		top=H-1;
		// 将第一列和最后一列【方格】置1,控制【方块】不超出游戏区域
		for(i=0; i<H; i++)
		{ cells[0][i]=1;	cells[W+1][i]=1;	}
		// 将最底下一行【方格】置1,控制【方块】不超出游戏区域
		for(i=0; i<W+2; i++)	cells[i][H-1]=1;
		// 其他【方格】置0,游戏方块只能在这里移动
		for(i=1; i<=W; i++)
			for(j=0; j<H-1; j++)
				cells[i][j]=0;
		return 0;

	case MS_NEWBLOCK:
		flag=0;         // flag表示【方块】旋转了几次
		for(i=top; i<H-1; i++)
		{
			lines =0;
			// 循环语句检查是否有某一行全部被【方格】都填满
			for(j=1; j<=W+1; j++)
				if(! cells[j][i]) 
				{	lines=1;	break;	}
			// 若该行被填满,则将上一行的填充状态复制到该行,依此类推
			// 即从该行开始,所有的【方格】都下移一行
			if(!lines)
			{	for(j=1;j<W+1; j++)
					for(k=i; k>=top; k--)
						cells[j][k]=cells[j][k-1];
				top++;
				InvalidateRect (hwnd, NULL, TRUE);
			}
		}
		// 产生随机数0~7,分别代表【方块】的7种形状
		srand( (unsigned)time( NULL ) );
		sel =rand()%7;
		//【方块】形状初始化
		//【方块】的形状由其每个【方格】的位置决定
		// 游戏区宽W=22,block[?][0]=9/10/11/12,block[?][1]=0/1/2
		// 这样【方块】初始位置在游戏区的最顶部的中央 
		switch(sel)
		{
		case 0:
			// ▓▓
			// ▓▓
			org[0][0]=block[0][0] =10;	org[0][1]=block[0][1] =0;
			org[1][0]=block[1][0] =11;	org[1][1]=block[1][1] =0;
			org[2][0]=block[2][0] =10;	org[2][1]=block[2][1] =1;
			org[3][0]=block[3][0] =11;	org[3][1]=block[3][1] =1;
			break;

		case 1:
			// ▓▓▓▓
			org[0][0]=block[0][0] =9;	org[0][1]=block[0][1] =0;
			org[1][0]=block[1][0] =10;	org[1][1]=block[1][1] =0;
			org[2][0]=block[2][0] =11;	org[2][1]=block[2][1] =0;
			org[3][0]=block[3][0] =12;	org[3][1]=block[3][1] =0;
			break;

		case 2:
			//▓
			//▓▓
			//  ▓
			org[0][0]=block[0][0] =10;	org[0][1]=block[0][1] =0;
			org[1][0]=block[1][0] =10;	org[1][1]=block[1][1] =1;
			org[2][0]=block[2][0] =11;	org[2][1]=block[2][1] =1;
			org[3][0]=block[3][0] =11;	org[3][1]=block[3][1] =2;
			break;

		case 3:
			//  ▓
			//▓▓
			//▓
			org[0][0]=block[0][0] =11;	org[0][1]=block[0][1] =0;
			org[1][0]=block[1][0] =11;	org[1][1]=block[1][1] =1;
			org[2][0]=block[2][0] =10;	org[2][1]=block[2][1] =1;
			org[3][0]=block[3][0] =10;	org[3][1]=block[3][1] =2;
			break;
			
		case 4:
			//▓
			//▓
			//▓▓
			org[0][0]=block[0][0] =10;	org[0][1]=block[0][1] =0;
			org[1][0]=block[1][0] =10;	org[1][1]=block[1][1] =1;
			org[2][0]=block[2][0] =10;	org[2][1]=block[2][1] =2;
			org[3][0]=block[3][0] =11;	org[3][1]=block[3][1] =2;
			break;

		case 5:
			//  ▓
			//  ▓
			//▓▓
			org[0][0]=block[0][0] =10;	org[0][1]=block[0][1] =0;
			org[1][0]=block[1][0] =10;	org[1][1]=block[1][1] =1;
			org[2][0]=block[2][0] =10;	org[2][1]=block[2][1] =2;
			org[3][0]=block[3][0] =9;	org[3][1]=block[3][1] =2;
			break;
		case 6:
			//  ▓
			//▓▓▓
			org[0][0]=block[0][0] =10;	org[0][1]=block[0][1] =0;
			org[1][0]=block[1][0] =9;	org[1][1]=block[1][1] =1;
			org[2][0]=block[2][0] =10;	org[2][1]=block[2][1] =1;
			org[3][0]=block[3][0] =11;	org[3][1]=block[3][1] =1;
			break;

		default:
			SendMessage (hwnd, MS_NEWBLOCK, 0, 0);
			break;
		}
		return 0;

	case WM_TIMER:
		// 每个时间节拍【方块】自动下移一行
		for(i=0; i<4; i++)
			block[i][1]++;
		// 检查【方块】下移是否被档住,即判断下移后新位置是否有【方格】
		for(i=0; i<4; i++)
			if(cells[ block[i][0] ][ block[i][1] ])
			{ 
				for(i=0; i<4; i++) 
					cells[ org[i][0] ][ org[i][1] ]=1; 
				if(top>org[0][1]-2) top=org[0][1]-2;
				if (top<1)
				{
					KillTimer (hwnd, 1);
					MessageBox (hwnd, "游戏结束,即将退出 !", "退出", MB_OK);
					PostQuitMessage (0);
				}
				SendMessage (hwnd, MS_NEWBLOCK, 0, 0);
				return 0;
			}
		SendMessage (hwnd, MS_DRAW, 0, 0);
		return 0;

	// 响应键盘控制
	case WM_KEYDOWN:
		r=0;
		switch((int)wParam)
		{
		case VK_LEFT:
			for(i=0; i<4; i++)
				block[i][0]--;
			break;

		case VK_RIGHT:
			for(i=0; i<4; i++)
				block[i][0]++;
			break;
		case VK_DOWN:
			for(i=0; i<4; i++)
				block[i][1]++;
			break;

		// 按[向上键],【方块】顺时针旋转
		//【方块】的旋转不是真正的旋转,而是根据不同的【方块】形状和
		// 该【方块】旋转过的次数来移动其中的一个或几个【方格】,从而
		// 达到旋转的效果 这样做很复杂,算法不够理想,但是能够保持【方
		// 块】旋转时的重心比较稳定。
		case VK_UP:
			r=1;
			flag++;     //【方块】旋转加1
			switch(sel) // sel代表当前【方块】的形状
			{
			case 0: break;

			case 1: 
				flag =flag%2;
				for(i=0; i<4; i++)
				{
					block[i][(flag+1)%2] =org[2][(flag+1)%2];
					block[i][flag] =org[2][flag]-2+i;
				}
				break;

			case 2:
				flag =flag%2;
				if(flag)
				{	block[0][1] +=2;	block[3][0] -=2;	}
				else
				{	block[0][1] -=2;	block[3][0] +=2;	}
				break;

			case 3:
				flag =flag%2;
				if(flag)
				{	block[0][1] +=2;	block[3][0] +=2;	}
				else
				{	block[0][1] -=2;	block[3][0] -=2;	}
				break;

			case 4:
				flag=flag%4;
				switch(flag)
				{
				case 0:
					block[2][0] +=2;	block[3][0] +=2;
					block[2][1] +=1;	block[3][1] +=1;
					break;
				case 1:
					block[2][0] +=1;	block[3][0] +=1;
					block[2][1] -=2;	block[3][1] -=2;
					break;
				case 2:
					block[2][0] -=2;	block[3][0] -=2;
					block[2][1] -=1;	block[3][1] -=1;
					break;
				case 3:
					block[2][0] -=1;	block[3][0] -=1;
					block[2][1] +=2;	block[3][1] +=2;
					break;
				}
				break;

			case 5:
				flag=flag%4;
				switch(flag)
				{
				case 0:
					block[2][0] +=1;	block[3][0] +=1;
					block[2][1] +=2;	block[3][1] +=2;
					break;
				case 1:
					block[2][0] +=2;	block[3][0] +=2;
					block[2][1] -=1;	block[3][1] -=1;
					break;
				case 2:
					block[2][0] -=1;	block[3][0] -=1;
					block[2][1] -=2;	block[3][1] -=2;
					break;
				case 3:
					block[2][0] -=2;	block[3][0] -=2;
					block[2][1] +=1;	block[3][1] +=1;
					break;
				}
				break;

			case 6:
				flag =flag%4;
				switch(flag)
				{
				case 0:
					block[0][0]++; block[0][1]--;
					block[1][0]--; block[1][1]--;
					block[3][0]++; block[3][1]++;
					break;
				case 1:
					block[1][0]++; block[1][1]++; break;
				case 2:
					block[0][0]--; block[0][1]++; break;
				case 3:
					block[3][0]--; block[3][1]--; break;
				}
				break;
			}
			break;
		}
		// 判断【方块】旋转后新位置是否有【方格】,若有,则旋转取消
		for(i=0; i<4; i++)
			if(cells[ block[i][0] ][ block[i][1] ])
			{ 
				if(r) flag +=3;
				for(i=0; i<4; i++)
					for(j=0; j<2; j++)
						block[i][j]=org[i][j];
				return 0;
			}
		SendMessage(hwnd, MS_DRAW, 0, 0);;
		return 0;

	// 清除当前【方块】,并在新的位置重新绘制【方块】
	case MS_DRAW:
		hdc =GetDC (hwnd);
		Cover (hdc, org);
		for(i=0; i<4; i++)
			for(j=0; j<2; j++)
				org[i][j]=block[i][j];
		DrawBlock (hdc,block);
		ReleaseDC (hwnd, hdc);
		return 0;

	// 按照【方格矩阵】重绘游戏区域的【方格】
	case WM_PAINT:
		hdc =BeginPaint (hwnd, &ps);
		hpen =CreatePen (PS_SOLID,1,RGB(255,255,255));
		SelectObject (hdc,hpen);
		for (i=top; i<H-1; i++)
			for(j=1; j<=W; j++)
				if( cells[j][i] ) 
					DrawCell (hdc, (j-1)*CELL, (i-1)*CELL, j*CELL, i*CELL);
		DeleteObject (hpen);
		EndPaint (hwnd, &ps);
		return 0;

	case WM_DESTROY:
		KillTimer (hwnd, 1);
		PostQuitMessage (0);
		return 0;
	}

	return DefWindowProc (hwnd, iMsg, wParam, lParam);
}

/************************************************************/

/* 结束
 * 注释时间: 2003/01/04 SAT
 * 于 广东省三水市建行宿舍
 */

 /************************************************************/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -