C语言学习—俄罗斯方块

目录

一、目的

二、主要思路

三、实现

1、游戏准备

1)宏定义

2)库函数 

3)全局变量

5) 色值和设置颜色函数

6)光标跳转和隐藏

1    光标跳转函数

2    光标隐藏函数

2、游戏界面

1)菜单

2)规则界面

3)结束界面 

 4)游戏中界面

3、游戏方块初始化

1)游戏方块

2)定义方块旋转函数

 3)初始化28种方块

 4、在游戏界面画出游戏方块

5、空格覆盖函数

6、合法性判断

7、输入位置信息

8、清除满行的方块

1)方块是否满行

2)空格覆盖游戏区内所有方块并重新打印

9、游戏结束

10、game()

四、总代码

1、头文件

1)game.h :宏定义,声明函数,变量等

2、源文件

1)game.cpp :定义函数、变量

2)Tetris.cpp :游戏的主体函数


一、目的

http://www.minesweeper.cn/falling/

C语言实现俄罗斯方块

二、主要思路

1、定义游戏框架结构体,用于存储方块在游戏中的位置信息和颜色信息

2、定义方块结构体,用于存储7种方块,同时存储之后每种方块旋转后的形态,总共4次,就是一共储存28种方块

3、操纵键盘需要用到的键位值

4、游戏菜单,游戏中界面,游戏结束界面,还有游戏规则界面

5、方块打印

6、空格覆盖

7、合法性判断

8、game()

三、实现

1、游戏准备

1)宏定义

#define row 28 //游戏行数
#define col 18 //游戏列数
#define ROW row+2 //游戏方框行数,包括提示区等
#define COL col+12 //游戏方框列数,包括提示区等

2)库函数 

#include <iostream>

#include<Windows.h>//实现窗口操作

#include<stdio.h>

#include<time.h>//取时间戳重定义rand()函数

#include<stdlib.h>//引用rand()取随机数

/*关于键盘的头文件,主要使用getch()监控键盘操作
和使用kbhit()监控键盘是否被操作*/
#include<conio.h>

3)全局变量

//获取控制台句柄
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);

//用于记录方块位置、颜色信息
struct Rec_and_color
{
	int rec[ROW][COL] = { 0 };//位置
	int c[ROW][COL] = { 0 };//颜色
}r_c;

struct Diamonds//用于存储方块信息,包括7个方块和旋转后的方块
{
	int diamonds[4][4];
}dia[7][4];

//7个方块的颜色信息
int COLOR[7] = { 3,9,10,11,12,13,14 };

//游戏中的等级、得分记录
int grade1 = 0;//等级
int grade2 = 0;//得分

4)键码值

ESC空格
728075772732

读取键盘操作

char ch = _getch();

5) 色值和设置颜色函数

色值

0123456789101112131415
深蓝深绿深蓝绿深红紫色暗黄亮蓝亮绿亮蓝绿亮白

 头文件包含的设置颜色函数

BOOL SetConsoleTextAttribute(句柄,色值);

 定义修改颜色函数

//设置颜色函数
void color(int num)
{
	SetConsoleTextAttribute(handle, num);
}

6)光标跳转和隐藏

1    光标跳转函数

头文件包含的光标跳转函数

SetConsoleCursorPosition(句柄,光标位置结构体);

定义光标跳转函数

//光标跳转函数
void cursor_goto(int x,int y)
{
	//设置光标位置结构体
	COORD x_y;
	x_y.X = x;
	x_y.Y = y;
	//光标跳转
	SetConsoleCursorPosition(handle, x_y);
}
2    光标隐藏函数

头文件包含的光标隐藏函数

SetConsoleCursorInfo(句柄, 取地址光标信息结构体);

自带的光标信息结构体

typedef struct _CONSOLE_CURSOR_INFO
{
    DWORD dwSize;//光标百分比厚度1~100
    BOLL bVisible;//光标是否可见
}CONSOLE_CURSOR_INFO,*PCONSOLE_CURSOR_INFO;

 定义光标隐藏函数

//隐藏光标函数
void cursor_hide()
{
	//设置光标信息结构体
	CONSOLE_CURSOR_INFO curinfo;
	curinfo.dwSize = 1;
	curinfo.bVisible = FALSE;
	//设置光标信息
	SetConsoleCursorInfo(handle, &curinfo);
}

2、游戏界面

1)菜单

//游戏菜单界面
void BEGIN()
{
	color(14);
	cursor_goto(17, 3);
	printf("=======================");
	color(11);
	cursor_goto(18, 5);
	printf("俄   罗   斯   方   块");
	color(14);
	cursor_goto(17, 7);
	printf("=======================");

	color(15);
	cursor_goto(20, 12);
	printf("1.【 开 始 游 戏 】");

	cursor_goto(20, 15);
	printf("2.【 游 戏 规 则】");

	cursor_goto(18, 18);
	printf("ESC.【 退 出 游 戏 】");


	for (int i = 0; i < ROW; i++)
	{
		for (int j = 0; j < COL; j++)
		{
			color(1+rand()%15);
			if (i == 0 || i == ROW - 1)
			{
				cursor_goto(2 * j, i);
				printf("■");
			}
			else if (j == 0 || j == COL - 1)
			{
				cursor_goto(2 * j, i);
				printf("■");
			}
		}
	}
}

2)规则界面

//游戏规则界面
void rlues()
{
	color(14);
	cursor_goto(17, 3);
	printf("=======================");
	color(11);
	cursor_goto(18, 5);
	printf("   游   戏   规   则   ");
	color(14);
	cursor_goto(17, 7);
	printf("=======================");

	color(10);
	cursor_goto(10,10);
	printf("1.不同形状的小方块从屏幕上方落下玩");
	cursor_goto(12, 11);
	printf("家通过调整方块的位置和方向使它们");
	cursor_goto(12, 12);
	printf("在屏幕底部拼出完整的一行或几行");

	cursor_goto(10, 14);
	printf("2.每消除一行,分数增加100");
	cursor_goto(12, 15);
	printf("每消除一行,分数增加100,每累计");
	cursor_goto(12, 16);
	printf("1000分,会提升一个等级");

	cursor_goto(10, 18);
	printf("3.提升等级会使方块下落速度加快,游戏");
	cursor_goto(12, 19);
	printf("难度加大");

	for (int i = 0; i < ROW; i++)
	{
		for (int j = 0; j < COL; j++)
		{
			color(1 + rand() % 15);
			if (i == 0 || i == ROW - 1)
			{
				cursor_goto(2 * j, i);
				printf("■");
			}
			else if (j == 0 || j == COL - 1)
			{
				cursor_goto(2 * j, i);
				printf("■");
			}
		}
	}

next:

	char ch = _getch();
	switch (ch)
	{
	case 27:
		return;
	default:
		goto next;//如果不是ESC键就从next处继续执行代码
	}
}

3)结束界面 

//游戏结束界面
void END()
{
	system("cls");
	color(12);
	cursor_goto(17, 5);
	printf("■■■■■■   ■■    ■   ■■■■");
	cursor_goto(17, 6);
	printf("■        ■ ■   ■   ■    ■");
	cursor_goto(17, 7);
	printf("■■■■■■   ■  ■  ■   ■     ■");
	cursor_goto(17, 8);
	printf("■        ■   ■ ■   ■    ■");
	cursor_goto(17, 9);
	printf("■■■■■■   ■    ■■   ■■■■");

	color(11);
	cursor_goto(20, 13);
	printf("你的等级是 : %d ",grade1);
	cursor_goto(20, 14);
	printf("你的得分是 : %d ",grade2);


	color(10);
	cursor_goto(16, 17);
	printf("->1.重 新 开 始 游 戏");
	cursor_goto(16, 20);
	printf("->ESC.退 出 游 戏");

	for (int i = 0; i < ROW; i++)
	{
		for (int j = 0; j < COL; j++)
		{
			color(1 + rand() % 15);
			if (i == 0 || i == ROW - 1)
			{
				cursor_goto(2 * j, i);
				printf("■");
			}
			else if (j == 0 || j == COL - 1)
			{
				cursor_goto(2 * j, i);
				printf("■");
			}
		}
	}

next:

	char ch = _getch();
	switch (ch)
	{
	case '1':
		game();
	case 27:
		return;
	default:
		goto next;//如果不是ESC键或1键就从next处继续执行代码
	}
}

 4)游戏中界面

//初始化游戏方框
void initial_game_box()
{
	color(7);
	cursor_goto(2 * (col + 3), 2);
	printf("下一出现方块");
	cursor_goto(2 * (col + 4), ROW - 16);
	printf("←:右移");
	cursor_goto(2 * (col + 4), ROW - 14);
	printf("→:左移");
	cursor_goto(2 * (col + 4), ROW - 12);
	printf("↑:切换方块");
	cursor_goto(2 * (col + 4), ROW - 10);
	printf("↓:加速");
	cursor_goto(2 * (col + 4), ROW - 8);
	printf("space:暂停");
	cursor_goto(2 * (col + 4), ROW - 6);
	printf("R:重新开始");
	cursor_goto(2 * (col + 4), ROW - 4);
	printf("ESC:退出");

/*打印的同时把所处位置是否有方块输入到位置信息结构体
1代表有方块,0代表无方块*/
	for (int i = 0; i < ROW; i++)
	{
		for (int j = 0; j < COL; j++)
		{
			if (i == 0 || i == ROW - 1)
			{
				r_c.rec[i][j] = 1;
				r_c.c[i][j] = 15;
				cursor_goto(2*j, i);
				printf("■");
			}
			else if (j == 0 || j == col+1 || j == COL - 1)
			{
				r_c.rec[i][j] = 1;
				r_c.c[i][j] = 15;
				cursor_goto(2 * j, i);
				printf("■");
			}
			else
			{
				r_c.rec[i][j] = 0;
			}
			size_t num = ROW;
			if (i == (num / 3) && j > col)
			{
				r_c.rec[i][j] = 1;
				r_c.c[i][j] = 15;
				cursor_goto(2 * j, i);
				printf("■");
			}
		}
	}
}

3、游戏方块初始化

1)游戏方块

2)定义方块旋转函数

//将方块旋转保存在dia中
void Diamonds_spin(int rows,int cols)
{ 
	for (int i = 0; i < 4; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			dia[rows][cols].diamonds[i][j] = dia[rows][cols-1].diamonds[j][3-i];
		}
	}
}

 3)初始化28种方块

首先定义第一组7种初始方块,然后通过方块旋转函数,将第一组选转保存在第二组,第二组选择保存在第三组,循环三次就会有 4*7 == 28 种方块

//初使化方块
void initial_Diamonds()
{
	//T
	for (int j = 0; j < 3; j++)
		dia[0][0].diamonds[1][j] = 1;
	dia[0][0].diamonds[2][1] = 1;

	//L
	for (int i = 1; i > 0 && i < 4; i++)
		dia[1][0].diamonds[i][1] = 1;
	dia[1][0].diamonds[3][2] = 1;

	//J
	for (int i = 1; i > 0 && i < 4; i++)
		dia[2][0].diamonds[i][2] = 1;
	dia[2][0].diamonds[3][1] = 1;

	//Z
	for (int j = 0; j < 2; j++)
		dia[3][0].diamonds[1][j] = 1;
	for (int j = 1; j < 3; j++)
		dia[3][0].diamonds[2][j] = 1;

	//镜面Z
	for (int j = 1; j < 3; j++)
		dia[4][0].diamonds[1][j] = 1;
	for (int j = 0; j < 2; j++)
		dia[4][0].diamonds[2][j] = 1;

	//■
	for (int i = 1; i < 3; i++)
	{
		for (int j = 1; j < 3; j++)
		{
			dia[5][0].diamonds[i][j] = 1;
		}
	}

	//|
	for (int i = 0; i < 4; i++)
		dia[6][0].diamonds[i][1] = 1;

	//将第一组的方块进行转向存进第二组中,再将第二组。。。
	for (int i = 0; i < 7; i++)
	{
		for (int j = 1; j < 4; j++)
		{
			Diamonds_spin(i, j);
		}
	}
}

 4、在游戏界面画出游戏方块

当方块结构体里遇到 1 时打印,否则不打印

//画出方块
void draw(int shape,int form, int x, int y)
{
	for (int i = 0; i < 4; i++)
	{
		for (int j = 0; j < 4; j++)
		{
//判断(x+i) != 0 是因为x == 0的一行 是游戏方框的一部分,所以x == 0的一行不打印游戏方块 
			if ((dia[shape][form].diamonds[i][j] == 1) && ((x + i) != 0))
			{
				color(COLOR[shape]);
				cursor_goto(2 * (y + j), i + x);
				printf("■");
			}
		}
	}
}

5、空格覆盖函数

游戏方块在下移过程中需要覆盖之前打印好的方块,再打印下一个游戏方块

//空格覆盖函数
void space_print(int shape, int form,int x,int y)
{
	for (int i = 0; i < 4; i++)
	{
		for (int j = 0; j < 4; j++)
		{
//与画出游戏方块函数相同,空格不覆盖游戏方框
			if ((dia[shape][form].diamonds[i][j] == 1) && ((x + i) != 0))
			{
				cursor_goto(2*(y + j), i + x);
				printf("  ");
			}
		}
	}
}

6、合法性判断

通过游戏方块结构体和方块位置结构体进行合法性判断,因为两个结构体都是用 1 和 0 表示是否有方块,所以在移动过程中将要移动的位置和将两个结构体对应位置的方块信息都是 1 ,那么停止移动

//合法性判断
int legitimate(int shape, int form,int x,int y)
{
	for (int i = 0; i < 4; i++)
	{
		for (int j = 0; j < 4; j++)
		{
//这里判断 (x+i) > 0 是因为游戏方框里也储存的 1 从最上面打印的游戏方块不受游戏方框上层部分的影响 
			if ((dia[shape][form].diamonds[i][j] == 1)&& (r_c.rec[x + i][y + j] == 1) && ((x + i) > 0))
			{
				return 0;
			}
		}
	}
	return 1;

 如果合法返回 1 ,不合法返回 0 

7、输入位置信息

如果游戏方块下移过程中合法性判断函数返回 0 ,停止下移并且在停止下移位置输入方块位置和颜色信息

//在落点处输入位置信息
void scanf_rec(int shape, int form, int x, int y)
{
	for (int i = 0; i < 4; i++)	
	{
		for (int j = 0; j < 4; j++)
		{
			if (dia[shape][form].diamonds[i][j] == 1)
			{
				r_c.rec[x + i][j + y] = 1;
				r_c.c[x + i][j + y] = COLOR[shape];
			}
		}
	}
}

8、清除满行的方块

1)方块是否满行

通过方块位置结构体判断?行方块是否满行

满行的话将从该行开始,从该行(该行会不下移,且会被上一行覆盖)往上的方块位置、颜色信息下移,游戏方块除外

//判断是否满足清除一行的条件
void purge()
{
	for (int i = 1; (i > 0) && (i <= row); i++)
	{
		int k = 0;
		for (int j = 1; (j > 0) && (j <= col); j++)
		{
			if (r_c.rec[i][j] == 1)
				k++;
		}
		//如果一行都是有方块,那么将上层的方块覆盖到下层
		if (k == col)
		{
			grade2 += 100;
			if ((grade2 % 1000) == 0)
				grade1++;
			for (int n = i; n > 1; n--)
			{
				for (int m = 1; (m > 0) && (m <= col); m++)
				{
					r_c.rec[n][m] = r_c.rec[n - 1][m];
					r_c.c[n][m] = r_c.c[n - 1][m];
				}
			}
			printf_();
		}
	}
	
}

2)空格覆盖游戏区内所有方块并重新打印

//方块打印
void printf_()
{
	for (int i = 1; (i > 0) && (i <= row);i++)
	{
		for (int j = 1; (j > 0) && (j <= col); j++)
		{
			if (r_c.rec[i][j] == 1)
			{
				color(r_c.c[i][j]);
				cursor_goto(2 * j, i);
				printf("■");
			}
			else
			{
				cursor_goto(2 * j, i);
				printf("  ");
			}
		}
	}
}

9、游戏结束

通过方块位置结构体判断,游戏区(除游戏方框)最上一层有方块,那么游戏结束

//输
int lose()
{
	int k = 0;
	for (int j = 1; (j > 0) && (j <= col); j++)
	{
		if (r_c.rec[1][j] == 1)
			k++;
	}
	return k;
}

如果 k != 0 说明有方块,游戏结束

10、game()

游戏的主体逻辑

void game()
{
	grade1 = 0;
	grade2 = 0;

	system("cls");

	//游戏界面初始化
	initial_game_box();

	//方块信息初始化
	initial_Diamonds();

	//随机选取方块
	int shape = rand() % 7;
	int form = rand() % 4;

	while (1)
	{

		//随机选取下一方块
		int nshape = rand() % 7;
		int nform = rand() % 4;
		
		//将方块显示在提示区
		draw(nshape,nform, 4, col + 5);
		
		int y = col / 2, x = 0;//设置方块初始显示位置

		int n = 0;

		while (1)
		{
			//将方块显示在初始下落位置
			draw(shape, form, x, y);
			
			if (n == 0)
			{
				n = 15000 - (5 * grade1);
			}

			//判断键盘是否被敲击
			while (--n)
			{
				if (_kbhit() != 0)//如果键盘被敲击就退出循环
					break;
			}

			if (n == 0)//键盘未被敲击
			{
				if (legitimate(shape, form, x + 1, y) == 0)
				{
					scanf_rec(shape, form, x, y);
					purge();
					if (lose())
					{
						END();
						return;
					}
					break;
				}
				else
				{
					space_print(shape, form, x , y);
					x++;
				}
			}
			else//键盘被敲击
			{
				char ch = _getch();
				switch (ch)
				{
				case 72://上
					if (legitimate(shape, (form+1)%4, x + 1, y) == 1)
					{
						space_print(shape, form, x, y);
						x++;
						form = (form + 1) % 4;
					}
					break;
				case 80://下
					if (legitimate(shape, form, x + 1, y) == 1)
					{
						space_print(shape, form, x, y);
						x++;
					}
					break;
				case 75://左
					if (legitimate(shape, form, x, y - 1) == 1)
					{
						space_print(shape, form, x, y);
						y--;
					}
					break;
				case 77://右
					if (legitimate(shape, form, x, y + 1) == 1)
					{
						space_print(shape, form, x, y);
						y++;
					}
					break;
				case 27://ESC
					END();
					return;
				case 'r':
				case 'R':
					system("cls");
					game();
					break;
				case 32://SPACE
					system("pause > null");
					break;
				}
			}
		}
		space_print(nshape, nform, 4, col + 5);
		shape = nshape;
		form = nform;
	}
}

四、总代码

1、头文件

1)game.h :宏定义,声明函数,变量等

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1

#define row 28 //游戏行数
#define col 18 //游戏列数
#define ROW row+2 //游戏方框行数,包括提示区和分数区
#define COL col+12 //游戏方框列数,包括提示区和分数区

#include <iostream>
#include<Windows.h>
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#include<conio.h>//关于键盘的头文件

extern int grade1;
extern int grade2;

//隐藏光标函数
void cursor_hide();

//光标跳转函数
void cursor_goto(int x, int y);

//设置颜色函数
void color(int num);

//初始化游戏方框
void initial_game_box();

//将方块旋转保存在dia中
void Diamonds_spin(int rows, int cols);

//初使化方块
void initial_Diamonds();

//画出方块
void draw(int shape, int form, int x, int y);

//空格覆盖函数
void space_print(int shape, int form, int x, int y);

//合法性判断
int legitimate(int shape, int form, int x, int y);

//在落点处输入位置信息
void scanf_rec(int shape, int form, int x, int y);

//方块打印
void printf_();

//判断是否满足清除一行的条件
void purge();

//输
int lose();

//游戏菜单界面
void BEGIN();

//游戏结束界面
void END();

//游戏规则界面
void rlues();

//游戏主体逻辑
void game();

//主函数
int main();

2、源文件

1)game.cpp :定义函数、变量

#include"game.h"

//获取控制台句柄
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);

//用于记录方块位置、颜色信息
struct Rec_and_color
{
	int rec[ROW][COL] = { 0 };
	int c[ROW][COL] = { 0 };
}r_c;

struct Diamonds//用于存储方块信息,包括7个方块和旋转后的方块
{
	int diamonds[4][4];
}dia[7][4];

//7个方块的颜色信息
int COLOR[7] = { 3,9,10,11,12,13,14 };

//游戏中的等级、得分记录
int grade1 = 0;//等级
int grade2 = 0;//得分

//隐藏光标函数
void cursor_hide()
{
	//设置光标信息结构体
	CONSOLE_CURSOR_INFO curinfo;
	curinfo.dwSize = 1;
	curinfo.bVisible = FALSE;
	//设置光标信息
	SetConsoleCursorInfo(handle, &curinfo);
}

//光标跳转函数
void cursor_goto(int x,int y)
{
	//设置光标位置结构体
	COORD x_y;
	x_y.X = x;
	x_y.Y = y;
	//光标跳转
	SetConsoleCursorPosition(handle, x_y);
}

//设置颜色函数
void color(int num)
{
	SetConsoleTextAttribute(handle, num);
}

//初始化游戏方框
void initial_game_box()
{
	color(7);
	cursor_goto(2 * (col + 3), 2);
	printf("下一出现方块");
	cursor_goto(2 * (col + 4), ROW - 16);
	printf("←:右移");
	cursor_goto(2 * (col + 4), ROW - 14);
	printf("→:左移");
	cursor_goto(2 * (col + 4), ROW - 12);
	printf("↑:切换方块");
	cursor_goto(2 * (col + 4), ROW - 10);
	printf("↓:加速");
	cursor_goto(2 * (col + 4), ROW - 8);
	printf("space:暂停");
	cursor_goto(2 * (col + 4), ROW - 6);
	printf("R:重新开始");
	cursor_goto(2 * (col + 4), ROW - 4);
	printf("ESC:退出");
	for (int i = 0; i < ROW; i++)
	{
		for (int j = 0; j < COL; j++)
		{
			if (i == 0 || i == ROW - 1)
			{
				r_c.rec[i][j] = 1;
				r_c.c[i][j] = 15;
				cursor_goto(2*j, i);
				printf("■");
			}
			else if (j == 0 || j == col+1 || j == COL - 1)
			{
				r_c.rec[i][j] = 1;
				r_c.c[i][j] = 15;
				cursor_goto(2 * j, i);
				printf("■");
			}
			else
			{
				r_c.rec[i][j] = 0;
			}
			size_t num = ROW;
			if (i == (num / 3) && j > col)
			{
				r_c.rec[i][j] = 1;
				r_c.c[i][j] = 15;
				cursor_goto(2 * j, i);
				printf("■");
			}
		}
	}
}


//初使化方块
void initial_Diamonds()
{
	//T
	for (int j = 0; j < 3; j++)
		dia[0][0].diamonds[1][j] = 1;
	dia[0][0].diamonds[2][1] = 1;

	//L
	for (int i = 1; i > 0 && i < 4; i++)
		dia[1][0].diamonds[i][1] = 1;
	dia[1][0].diamonds[3][2] = 1;

	//J
	for (int i = 1; i > 0 && i < 4; i++)
		dia[2][0].diamonds[i][2] = 1;
	dia[2][0].diamonds[3][1] = 1;

	//Z
	for (int j = 0; j < 2; j++)
		dia[3][0].diamonds[1][j] = 1;
	for (int j = 1; j < 3; j++)
		dia[3][0].diamonds[2][j] = 1;

	//镜面Z
	for (int j = 1; j < 3; j++)
		dia[4][0].diamonds[1][j] = 1;
	for (int j = 0; j < 2; j++)
		dia[4][0].diamonds[2][j] = 1;

	//■
	for (int i = 1; i < 3; i++)
	{
		for (int j = 1; j < 3; j++)
		{
			dia[5][0].diamonds[i][j] = 1;
		}
	}

	//|
	for (int i = 0; i < 4; i++)
		dia[6][0].diamonds[i][1] = 1;

	//将第一组的方块进行转向存进第二组中,再将第二组。。。
	for (int i = 0; i < 7; i++)
	{
		for (int j = 1; j < 4; j++)
		{
			Diamonds_spin(i, j);
		}
	}
}

//将方块旋转保存在dia中
void Diamonds_spin(int rows,int cols)
{ 
	for (int i = 0; i < 4; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			dia[rows][cols].diamonds[i][j] = dia[rows][cols-1].diamonds[j][3-i];
		}
	}
}


//画出方块
void draw(int shape,int form, int x, int y)
{
	for (int i = 0; i < 4; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			if ((dia[shape][form].diamonds[i][j] == 1) && ((x + i) != 0))
			{
				color(COLOR[shape]);
				cursor_goto(2 * (y + j), i + x);
				printf("■");
			}
		}
	}
}

//空格覆盖函数
void space_print(int shape, int form,int x,int y)
{
	for (int i = 0; i < 4; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			if ((dia[shape][form].diamonds[i][j] == 1) && ((x + i) != 0))
			{
				cursor_goto(2*(y + j), i + x);
				printf("  ");
			}
		}
	}
}

//合法性判断
int legitimate(int shape, int form,int x,int y)
{
	for (int i = 0; i < 4; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			if (((dia[shape][form].diamonds[i][j] + r_c.rec[x + i][y + j]) > 1) && ((x + i) > 0))
			{
				return 0;
			}
		}
	}
	return 1;
}

//在落点处输入位置信息
void scanf_rec(int shape, int form, int x, int y)
{
	for (int i = 0; i < 4; i++)	
	{
		for (int j = 0; j < 4; j++)
		{
			if (dia[shape][form].diamonds[i][j] == 1)
			{
				r_c.rec[x + i][j + y] = 1;
				r_c.c[x + i][j + y] = COLOR[shape];
			}
		}
	}
}

//方块打印
void printf_()
{
	for (int i = 1; (i > 0) && (i <= row);i++)
	{
		for (int j = 1; (j > 0) && (j <= col); j++)
		{
			if (r_c.rec[i][j] == 1)
			{
				color(r_c.c[i][j]);
				cursor_goto(2 * j, i);
				printf("■");
			}
			else
			{
				cursor_goto(2 * j, i);
				printf("  ");
			}
		}
	}
}


//判断是否满足清除一行的条件
void purge()
{
	for (int i = 1; (i > 0) && (i <= row); i++)
	{
		int k = 0;
		for (int j = 1; (j > 0) && (j <= col); j++)
		{
			if (r_c.rec[i][j] == 1)
				k++;
		}
		//如果一行都是有方块,那么将上层的方块覆盖到下层
		if (k == col)
		{
			grade2 += 100;
			if ((grade2 % 1000) == 0)
				grade1++;
			for (int n = i; n > 1; n--)
			{
				for (int m = 1; (m > 0) && (m <= col); m++)
				{
					r_c.rec[n][m] = r_c.rec[n - 1][m];
					r_c.c[n][m] = r_c.c[n - 1][m];
				}
			}
			printf_();
		}
	}
	
}

//输
int lose()
{
	int k = 0;
	for (int j = 1; (j > 0) && (j <= col); j++)
	{
		if (r_c.rec[1][j] == 1)
			k++;
	}
	return k;
}

//游戏结束界面
void END()
{
	system("cls");
	color(12);
	cursor_goto(17, 5);
	printf("■■■■■■   ■■    ■   ■■■■");
	cursor_goto(17, 6);
	printf("■        ■ ■   ■   ■    ■");
	cursor_goto(17, 7);
	printf("■■■■■■   ■  ■  ■   ■     ■");
	cursor_goto(17, 8);
	printf("■        ■   ■ ■   ■    ■");
	cursor_goto(17, 9);
	printf("■■■■■■   ■    ■■   ■■■■");

	color(11);
	cursor_goto(20, 13);
	printf("你的等级是 : %d ",grade1);
	cursor_goto(20, 14);
	printf("你的得分是 : %d ",grade2);


	color(10);
	cursor_goto(16, 17);
	printf("->1.重 新 开 始 游 戏");
	cursor_goto(16, 20);
	printf("->ESC.退 出 游 戏");

	for (int i = 0; i < ROW; i++)
	{
		for (int j = 0; j < COL; j++)
		{
			color(1 + rand() % 15);
			if (i == 0 || i == ROW - 1)
			{
				cursor_goto(2 * j, i);
				printf("■");
			}
			else if (j == 0 || j == COL - 1)
			{
				cursor_goto(2 * j, i);
				printf("■");
			}
		}
	}

next:

	char ch = _getch();
	switch (ch)
	{
	case '1':
		game();
	case 27:
		return;
	default:
		goto next;//如果不是ESC键或1键就从next处继续执行代码
	}
}

//游戏菜单界面
void BEGIN()
{
	color(14);
	cursor_goto(17, 3);
	printf("=======================");
	color(11);
	cursor_goto(18, 5);
	printf("俄   罗   斯   方   块");
	color(14);
	cursor_goto(17, 7);
	printf("=======================");

	color(15);
	cursor_goto(20, 12);
	printf("1.【 开 始 游 戏 】");

	cursor_goto(20, 15);
	printf("2.【 游 戏 规 则】");

	cursor_goto(18, 18);
	printf("ESC.【 退 出 游 戏 】");


	for (int i = 0; i < ROW; i++)
	{
		for (int j = 0; j < COL; j++)
		{
			color(1+rand()%15);
			if (i == 0 || i == ROW - 1)
			{
				cursor_goto(2 * j, i);
				printf("■");
			}
			else if (j == 0 || j == COL - 1)
			{
				cursor_goto(2 * j, i);
				printf("■");
			}
		}
	}
}

//游戏规则界面
void rlues()
{
	color(14);
	cursor_goto(17, 3);
	printf("=======================");
	color(11);
	cursor_goto(18, 5);
	printf("   游   戏   规   则   ");
	color(14);
	cursor_goto(17, 7);
	printf("=======================");

	color(10);
	cursor_goto(10,10);
	printf("1.不同形状的小方块从屏幕上方落下玩");
	cursor_goto(12, 11);
	printf("家通过调整方块的位置和方向使它们");
	cursor_goto(12, 12);
	printf("在屏幕底部拼出完整的一行或几行");

	cursor_goto(10, 14);
	printf("2.每消除一行,分数增加100");
	cursor_goto(12, 15);
	printf("每消除一行,分数增加100,每累计");
	cursor_goto(12, 16);
	printf("1000分,会提升一个等级");

	cursor_goto(10, 18);
	printf("3.提升等级会使方块下落速度加快,游戏");
	cursor_goto(12, 19);
	printf("难度加大");

	for (int i = 0; i < ROW; i++)
	{
		for (int j = 0; j < COL; j++)
		{
			color(1 + rand() % 15);
			if (i == 0 || i == ROW - 1)
			{
				cursor_goto(2 * j, i);
				printf("■");
			}
			else if (j == 0 || j == COL - 1)
			{
				cursor_goto(2 * j, i);
				printf("■");
			}
		}
	}

next:

	char ch = _getch();
	switch (ch)
	{
	case 27:
		return;
	default:
		goto next;//如果不是ESC键就从next处继续执行代码
	}
}

2)Tetris.cpp :游戏的主体函数

#include"game.h"

void game()
{
	grade1 = 0;
	grade2 = 0;

	system("cls");

	//游戏界面初始化
	initial_game_box();

	//方块信息初始化
	initial_Diamonds();

	//随机选取方块
	int shape = rand() % 7;
	int form = rand() % 4;

	while (1)
	{

		//随机选取下一方块
		int nshape = rand() % 7;
		int nform = rand() % 4;
		
		//将方块显示在提示区
		draw(nshape,nform, 4, col + 5);
		
		int y = col / 2, x = 0;//设置方块初始显示位置

		int n = 0;

		while (1)
		{
			//将方块显示在初始下落位置
			draw(shape, form, x, y);
			
			if (n == 0)
			{
				n = 15000 - (5 * grade1);
			}

			//判断键盘是否被敲击
			while (--n)
			{
				if (_kbhit() != 0)//如果键盘被敲击就退出循环
					break;
			}

			if (n == 0)//键盘未被敲击
			{
				if (legitimate(shape, form, x + 1, y) == 0)
				{
					scanf_rec(shape, form, x, y);
					purge();
					if (lose())
					{
						END();
						return;
					}
					break;
				}
				else
				{
					space_print(shape, form, x , y);
					x++;
				}
			}
			else//键盘被敲击
			{
				char ch = _getch();
				switch (ch)
				{
				case 72://上
					if (legitimate(shape, (form+1)%4, x + 1, y) == 1)
					{
						space_print(shape, form, x, y);
						x++;
						form = (form + 1) % 4;
					}
					break;
				case 80://下
					if (legitimate(shape, form, x + 1, y) == 1)
					{
						space_print(shape, form, x, y);
						x++;
					}
					break;
				case 75://左
					if (legitimate(shape, form, x, y - 1) == 1)
					{
						space_print(shape, form, x, y);
						y--;
					}
					break;
				case 77://右
					if (legitimate(shape, form, x, y + 1) == 1)
					{
						space_print(shape, form, x, y);
						y++;
					}
					break;
				case 27://ESC
					END();
					return;
				case 'r':
				case 'R':
					system("cls");
					game();
					break;
				case 32://SPACE
					system("pause > null");
					break;
				}
			}
		}
		space_print(nshape, nform, 4, col + 5);
		shape = nshape;
		form = nform;
	}
}

int main()
{
	srand((unsigned int)time(NULL));

	//隐藏光标
	cursor_hide();
	
	system("cls");
	//游戏菜单
	BEGIN();

	char ch = _getch();

	switch (ch)
	{
	case '1':
		system("cls");
		game();
		break;
	case '2':
		system("cls");
		rlues();
		main();
	case 27://ESC
		break;
	default:
		break;
	}
	return 0;
}

  • 16
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值