游戏人生,玩物丧志系列:俄罗斯方块(注意开发环境VS2019)
tetris.h头文件
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<windows.h> //windows系统函数
#include<stdbool.h> //布尔型头文件,C语言没有布尔类型的基本数据类型
#include<time.h> //计时处理
#include<conio.h> //day6 Console Input/Output(控制台输入输出),用户通过按键盘产生的对应操作
//游戏区域位置设置
#define COL_BEGIN 2 //下标都从0开始
#define COL_END 14
#define ROW_BEGIN 4 //游戏池上留出4行,下留出2行,模拟方块缓慢落下
#define ROW_END 26
//利用结构体存储游戏相关数据
typedef struct TetrisManager
{
unsigned int pool[28]; //游戏池(包括左右边界(半角))
int x; //当前方块x坐标,此处坐标为方块左上角坐标
int y; //当前方块y坐标
int type[3]; //当前、下一个、下下一个方块的类型
int orientation[3]; //当前、下一个、下下一个方块的旋转状态
unsigned score; //得分
unsigned erasedcount[4]; //消去行数
unsigned erasedtotal; //消行总数
unsigned tetriscount[7]; //各方块数
unsigned tetristotal; //方块总数
bool dead; //挂
}Manager;
//以下结构体存储游戏控制相关数据
typedef struct TetrisControl
{
bool pause; //暂停
bool clockwise; //控制旋转方向是否为顺时针,true为顺时针
int direction; //移动方向:0向左移动,1向右移动
//游戏池内每格的颜色
int color[28][16];
}Control;
HANDLE output; //控制台输出句柄
//7种方块的4种旋转状态(4位一行)
static const unsigned int TetrisTable[7][4] =
{
{ 0x2222,0x00f0,0x2222,0x00f0 },//I型
{ 0x0072,0x04c4,0x0027,0x08c8 },//T型
{ 0x4460,0x0740,0x0622,0x02e0 },//L型
{ 0x0226,0x0470,0x0322,0x0071 },//J型
{ 0x0063,0x0264,0x0063,0x0264 },//Z型
{ 0x06c0,0x08c4,0x06c0,0x08c4 },//S型
{ 0x0660,0x0660,0x0660,0x0660 },//O型
};
//初始状态的游戏池
//每个元素表示游戏池的一行,两端(边界)各置2个1,底部2行全置为1,便于进行碰撞检测
//顶部4行用于给方块,但不显示出来
//再除去底部2行,显示出来的游戏池高度为22行
static const unsigned int gs_uInitialTetrisPool[28] =
{
0xc003,0xc003,0xc003,0xc003,0xc003,0xc003,0xc003,0xc003,0xc003,
0xc003,0xc003,0xc003,0xc003,0xc003,0xc003,0xc003,0xc003,0xc003,
0xc003,0xc003,0xc003,0xc003,0xc003,0xc003,0xc003,0xc003,0xffff,
0xffff
};
//函数声明(如果使用全局变量方式实现,就没必要传形参了)
//初始化游戏
void initGame(Manager* manager, Control* control);
//void initGame();
//显示提示信息
void printPrompting();
//显示得分信息
void printScore(const Manager* manager);
//显示游戏池边界
void printPoolBorder();
//以全角定位
void gotoxyWithFullwidth(short x, short y);
//开始游戏
void startGame(Manager* manager, Control* control);
//显示下一个和下下一个方块
void printNextTetris(const Manager* manager);
//day3
//显示游戏池
void printTetrisPool(Manager* manager, Control* control);
//初始化方块(给一个方块)
void initTetris(Manager* manager);
//插入方块
void insertTetris(Manager* manager);
//设置游戏池方格颜色
void SetPoolColor(const Manager* manager, Control* control);
//day4
//显示当前方块
void printCurrentTetris(const Manager* manager, Control* control);
//碰撞检测
bool checkCollision(const Manager* manager);
//消去行检测
bool checkErasing(Manager* manager, Control* control);
//移除方块
void removeTetris(Manager* manager);
//day5
//向下移动方块
void moveDownTetris(Manager* manager, Control* control);
//运行游戏
void runGame(Manager* manager, Control* control);
//水平移动方块
void horzMoveTetris(Manager* manager, Control* control);
//day6
//按键按下
void keydownControl(Manager* manager, Control* control, int key);
//day7
//旋转方块
void rotateTetris(Manager* manager, Control* control);
//方块直接落地
void dropDownTetris(Manager* manager, Control* control);
//再来一次
bool ifplayAgain();
入口文件
#include<cstdio>
#include"tetris.h"
#if 1
int main()
{
Manager manager;
Control control;
initGame(&manager, &control);
//initGame();
/* printPrompting();
printPoolBorder();
printScore(&manager);
printNextTetris(&manager);
printTetrisPool(&manager,&control);
printCurrentTetris(&manager,&control); */
do {
printPrompting();
printPoolBorder();
// printScore(&manager); //day5将其并入初始化方块函数中
// printNextTetris(&manager); //day5将其并入初始化方块函数中
// printTetrisPool(&manager,&control); //day5将其放入向下移动方块函数中
runGame(&manager, &control); //运行游戏
//day7
if (ifplayAgain()) //再来一次
{
//定位,再清屏
SetConsoleTextAttribute(output, 0x7);
system("cls");
//重新开始游戏
startGame(&manager, &control);
}
else
{
break;
}
} while (1);
gotoxyWithFullwidth(0, 0);
//关闭句柄
CloseHandle(output); //系统资源,用了要还的,也就是说用完后一定要closehandle关闭之,如果不这么做,你系统的句柄资源很快就用光了
return 0;
}
//初始化游戏
//void initGame()
void initGame(Manager* manager, Control* control)
{
//获取控制台输出句柄
output = GetStdHandle(STD_OUTPUT_HANDLE);
//定义光标隐藏变量并初始化
CONSOLE_CURSOR_INFO info = { 1,FALSE };
//设置光标隐藏
SetConsoleCursorInfo(output, &info);
//设置控制台标题
SetConsoleTitle(L"俄罗斯方块");
//day2增加开始游戏模块
startGame(manager, control);
}
//以全角定位
void gotoxyWithFullwidth(short x, short y)
{
static COORD pos;
pos.X = (2 * x); //左移1,*2使坐标改变为两个像素点距离
pos.Y = y;
SetConsoleCursorPosition(output, pos);
}
//显示提示信息
void printPrompting()
{
//设置文字颜色 1011 高亮+蓝+绿
SetConsoleTextAttribute(output, 0xB);
//设置提示信息的位置(26,10),实质上是(26*2=52,10)
gotoxyWithFullwidth(26, 10);
//输出文字
printf("■控制:"); //往下空一行
gotoxyWithFullwidth(27, 12);
printf("□向左移动:← A 4");
gotoxyWithFullwidth(27, 13);
printf("□向右移动:→ D 6");
gotoxyWithFullwidth(27, 14);
printf("□向下移动:↓ S 2");
gotoxyWithFullwidth(27, 15);
printf("□顺时旋转:↑ W 8");
gotoxyWithFullwidth(27, 16);
printf("□逆时移动:0");
gotoxyWithFullwidth(27, 17);
printf("□直接落地:空格");
gotoxyWithFullwidth(27, 18);
printf("□暂停游戏:回车");
gotoxyWithFullwidth(27, 23);
printf("■By:wanson");
}
//显示游戏池边界
void printPoolBorder()
{
int y;
//设置边界颜色(1111 0000 背景色高亮+蓝+绿+红)
SetConsoleTextAttribute(output, 0xf0);
for (y = ROW_BEGIN; y < ROW_END; y++) //不显示顶部4行和底部2行
{
//打印两条纵线
gotoxyWithFullwidth(10, y - 3); //左边一条纵线
printf("%2s", ""); //线宽
gotoxyWithFullwidth(23, y - 3); //右边一条纵线
printf("%2s", "");
}
//打印一条横线
gotoxyWithFullwidth(10, y - 3); //y-3=26-3=23 底部边界
printf("%28s", ""); //线宽,即长度为28
}
//显示得分信息
void printScore(const Manager* manager)
{
//内存空间全部置0 增加开始游戏函数(放在初始化函数中调用)后,将其移动到开始游戏的函数中
//memset(manager,0,sizeof(Manager));
static const char tetrisName[8] = "ITLJZSO";
int i;
//设置文字颜色 高亮+黄 1110
SetConsoleTextAttribute(output, 0xE);
//设置得分信息位置(2,2)
gotoxyWithFullwidth(2, 2);
printf("★得分:%u", manager->score);
//设置消行信息位置(1,6)
gotoxyWithFullwidth(1, 6);
printf("★消行总数:%u", manager->erasedtotal);
for (i = 0; i < 4; i++)
{
gotoxyWithFullwidth(2, 8 + i);
printf("☆消%d:%u", i + 1, manager->erasedcount[i]);
}
//设置方块总数位置(1,15)
gotoxyWithFullwidth(1, 15);
printf("★方块总数:%u", manager->tetristotal);
for (i = 0; i < 7; i++)
{
gotoxyWithFullwidth(2, 17 + i);
printf("☆%c形:%u", tetrisName[i], manager->tetriscount[i]);
}
}
//开始游戏
void startGame(Manager* manager, Control* control)
{
/*主要是初始化游戏相关值*/
//初始化结构体
//内存空间全部置0
memset(manager, 0, sizeof(Manager));
//day3
//初始化游戏池
memcpy(manager->pool, gs_uInitialTetrisPool, sizeof(unsigned int[28]));
//设置随机种子参数
srand((unsigned int)time(NULL));
//初始化下一个方块,随机生成
manager->type[1] = rand() % 7; //下一个类型
manager->orientation[1] = rand() % 4; //下一个的旋转状态
//初始化下下一个方块,随机生成
manager->type[2] = rand() % 7; //下下一个类型
manager->orientation[2] = rand() % 4; //下下一个的旋转状态
//day3
//控制内存空间全置为0
memset(control, 0, sizeof(Control));
//初始化方块
initTetris(manager);
//设置游戏池方格颜色
SetPoolColor(manager, control);
}
//显示下一个和下下一个方块
void printNextTetris(const Manager* manager)
{
int i, x;
unsigned int tetris; //用于存储下一个,下下一个方块
//设置边框颜色(前景色高亮+红+绿+蓝)
SetConsoleTextAttribute(output, 0x0f);
for (x = 26; x < 37; x++) //打印◇◇◇◇◇◇◇◇◇◇◇
{
gotoxyWithFullwidth(x, 1);
printf("◇");
}
gotoxyWithFullwidth(26, 2);
printf("◇%8s◇%8s◇", "", "");
gotoxyWithFullwidth(26, 3);
printf("◇%8s◇%8s◇", "", "");
gotoxyWithFullwidth(26, 4);
printf("◇%8s◇%8s◇", "", "");
gotoxyWithFullwidth(26, 5);
printf("◇%8s◇%8s◇", "", "");
gotoxyWithFullwidth(26, 6);
printf("◇◇◇◇◇◇◇◇◇◇◇");
//下一个方块,用相应颜色表示
tetris = TetrisTable[manager->type[1]][manager->orientation[1]];
//方块颜色高亮 按位或8(0~6之间的数(颜色)+8(前景色高亮))
SetConsoleTextAttribute(output, manager->type[1] | 8);
/*下一个方块显示位置: (27,2)(28,2)(29,2)(30,2)
(27,3)(28,3)(29,3)(30,3)
(27,4)(28,4)(29,4)(30,4)
(27,5)(28,5)(29,5)(30,5) */
for (i = 0; i < 16; i++)
{
gotoxyWithFullwidth((i % 4) + 27, (i >> 2) + 2); //i%4也可以写为i&3,右移2位,除以4取整
((tetris >> i) & 1) ? printf("■") : printf("%2s", ""); //将16位表示的方块(如0000 0000 1111 0000)逐位取出判断是0还是1,是1打印■,是0打印空格
// if((tetris >> i) & 1)
// printf("■");
// else
// printf("%2s","");
}
//下下一个方块,不显示颜色
tetris = TetrisTable[manager->type[2]][manager->orientation[2]];
SetConsoleTextAttribute(output, 8);
/* (32,2)(33,2)(34,2)(35,2)
(32,3)(33,3)(34,3)(35,3)
(32,4)(33,4)(34,4)(35,4)
(32,5)(33,5)(34,5)(35,5)*/
for (i = 0; i < 16; i++)
{
gotoxyWithFullwidth((i & 3) + 32, (i >> 2) + 2);
((tetris >> i) & 1) ? printf("■") : printf("%2s", "");
}
}
//显示游戏池
#define gotoxyInPool(x,y) gotoxyWithFullwidth(x+9,y-3)
void printTetrisPool(Manager* manager, Control* control)
{
int x, y;
//ROW_BEGIN 4 ROW_END 26
for (y = ROW_BEGIN; y < ROW_END; y++) //不显示顶部4行,底部2行
{
//gotoxyInPool(2,y);
gotoxyWithFullwidth(2 + 9, y - 3);
//定点到游戏池中的方格
//COL_BEGIN 2 COL_END 14
for (x = COL_BEGIN; x < COL_END; x++) //不显示左右边界2 3 4 5 (6 7 8 9) 10 11 12 13
{
if ((manager->pool[y] >> x) & 1) //游戏池的该位置有方块
{
//用相应颜色,显示一个实心方块
// SetConsoleTextAttribute(output,12);
SetConsoleTextAttribute(output, control->color[y][x]);
printf("■");
}
else
{
//没有方块,显示空白
SetConsoleTextAttribute(output, 0);
printf("%2s", "");
}
}
}
}
//初始化方块(给一个方块)
void initTetris(Manager* manager)
{
unsigned int tetris; //用于存放当前方块 16位
//下一个方块置为当前
manager->type[0] = manager->type[1];
manager->orientation[0] = manager->orientation[1];
//下下方块置为下一个
manager->type[1] = manager->type[2];
manager->orientation[1] = manager->orientation[2];
//随机生成下下一个方块
manager->type[2] = rand() % 7;
manager->orientation[2] = rand() % 4;
//当前方块
tetris = TetrisTable[manager->type[0]][manager->orientation[0]];
//设置当前方块y坐标,保证刚给出时只显示方块最下面一行
//这种实现使得玩家可以以很快的速度将方块落在不显示出来的顶部4行内
if (tetris & 0xF000) // 俄罗斯方块最先显示最下面一行(16位从后往前依次摆放数组)
{
manager->y = 0;
}
else {
manager->y = (tetris & 0xFF00) ? 1 : 2;
}
// manager->y=4; //能看到方块的行号
manager->y = 0; //开始游戏后需要设置为0,缓慢显示方格
manager->x = 6; //设置当前方块x坐标(游戏池中央4格)
//插入方块(day4插入前要先检测碰撞)
if (checkCollision(manager)) //检测到碰撞
{
manager->dead = true; //标记游戏结束
}
else
insertTetris(manager); //没有碰撞则插入方块
manager->tetristotal++; //方块总数
manager->tetriscount[manager->type[0]]++; //相应方块数
//day5
printNextTetris(manager); //显示下一个方块
printScore(manager); //显示得分信息
}
//插入方块
void insertTetris(Manager* manager)
{
unsigned int tetris; //存放当前方块 16位
tetris = TetrisTable[manager->type[0]][manager->orientation[0]];
//当前方块每4位取出,按位或到游戏池相应位置,即完成插入方块,4*4的数组由低位向高位输出
//manager->y=4,左移manager->x=6(6位),置于游戏池中间(如:0x0232)
manager->pool[manager->y + 0] |= (((tetris >> 0x0) & 0x000f) << manager->x);//y+0行
manager->pool[manager->y + 1] |= (((tetris >> 0x4) & 0x000f) << manager->x);//y+1行
manager->pool[manager->y + 2] |= (((tetris >> 0x8) & 0x000f) << manager->x);//y+2行
manager->pool[manager->y + 3] |= (((tetris >> 0xc) & 0x000f) << manager->x);//y+3行
}
//移除方块
void removeTetris(Manager* manager)
{
//当前方块 16位
unsigned int tetris = TetrisTable[manager->type[0]][manager->orientation[0]];
//当前方块每4位取出,按位取反后位与到游戏池相应位置,即完成移除方块
manager->pool[manager->y + 0] &= ~(((tetris >> 0x0) & 0x000f) << manager->x);
manager->pool[manager->y + 1] &= ~(((tetris >> 0x4) & 0x000f) << manager->x);
manager->pool[manager->y + 2] &= ~(((tetris >> 0x8) & 0x000f) << manager->x);
manager->pool[manager->y + 3] &= ~(((tetris >> 0xc) & 0x000f) << manager->x);
}
//设置游戏池方格颜色
void SetPoolColor(const Manager* manager, Control* control)
{
//显示游戏池时,先要在游戏池里判断某一方格有方块才显示相应方格的颜色
//这里只作设置颜色,没必要清除
//当移动方块或给一个方块时调用
int i, x, y;
//当前方块
unsigned int tetris; //16位
tetris = TetrisTable[manager->type[0]][manager->orientation[0]];
for (i = 0; i < 16; i++)
{
y = manager->y + (i >> 2); //待设置的行
if (y > ROW_END) //超过底部限制
{
break;
}
x = manager->x + (i & 3); //i%4 待设置的列
if ((tetris >> i) & 1) //检测到小方格属于当前方块区域
{
control->color[y][x] = (manager->type[0] | 8); //设置颜色
}
}
}
//显示当前方块
void printCurrentTetris(const Manager* manager, Control* control)
{
//显示当前方块是在方块移动后调用的,为擦去移动前的方块,需要扩展显示区域
//由于方块不可能向上移动,故不需要向下扩展
int x, y;
if (manager->y > ROW_BEGIN)
y = manager->y - 1; //向上扩展一行
else
y = ROW_BEGIN;
for (; y < ROW_END && y < manager->y + 4; y++)
{
if (manager->x > COL_BEGIN)
x = manager->x - 1; //向左扩展一列
else
x = COL_BEGIN;
//可写为:x=(manager->x > COL_BEGIN) ? (manager->x - 1):COL_BEGIN;
for (; x < COL_END && x < manager->x + 5; x++) //向右扩展一格
{
gotoxyInPool(x, y);
//定点到游戏池中的方格
if ((manager->pool[y] >> x) & 1) //游戏池中该方格有方块
{
SetConsoleTextAttribute(output, control->color[y][x]);
printf("■");
}
else //没有方块,显示空白
{
SetConsoleTextAttribute(output, 0);
printf("%2s", "");
}
}
}
}
//碰撞检测
bool checkCollision(const Manager* manager)
{
unsigned int tetris; //当前方块 16位
tetris = TetrisTable[manager->type[0]][manager->orientation[0]];
unsigned int dest = 0;
//首先获取当前方块在游戏池中的位置4*4
//游戏池中坐标x,y处小方格信息,按低到高存放在16位二进制的无符号数中
dest |= ((((manager->pool[manager->y + 0]) >> manager->x) << 0x0) & 0x000f);
//如果碰撞到之前保存在游戏池中的方块,则为1,否则为0没方块
dest |= ((((manager->pool[manager->y + 1]) >> manager->x) << 0x4) & 0x00f0);
dest |= ((((manager->pool[manager->y + 2]) >> manager->x) << 0x8) & 0x0f00);
dest |= ((((manager->pool[manager->y + 3]) >> manager->x) << 0xc) & 0xf000);
//每行游戏池的状态为1100 0000 0000 0011,底部1111 1111 1111 1111
//若游戏池某一行有方块,则状态改变(以横I为例):1100 0011 1100 0011,会产生碰撞
//检测碰撞实际上就是将游戏池中方块转换成一个16位二进制数,之后与当前方块进行与操作,看是否有重叠
//若当前方块与目标区域存在重叠,则发生碰撞,则与的结果不为0
return((dest & tetris) != 0);
}
//消行检测
bool checkErasing(Manager* manager, Control* control)
{
int count = 0;
static const unsigned score[5] = { 0,10,30,90,150 }; //消行得分
int y = manager->y + 3; //从下往上检测
/*int k=0;
for(;y>=manager->y+0 && k<4;y--,k++)
{
if(y<ROW_END && manager->pool[y]==0xffff) //有效区域内且一行已填满
{
count++;
//消除一行方块
memmove(manager->pool+1,manager->pool,sizeof(unsigned int)*y);
//颜色数组的元素随之移动
memmove(control->color[1],control->color[0],sizeof(int[16])*y);
}
}
*/
do {
if (y < ROW_END && manager->pool[y] == 0xffff) //有效区域内且一行已填满
{
count++;
//消除一行方块
memmove(manager->pool + 1, manager->pool, sizeof(unsigned int) * y);
//颜色数组的元素随之移动
memmove(control->color[1], control->color[0], sizeof(int[16]) * y);
}
else {
--y;
}
} while (y >= manager->y);
manager->erasedtotal += count; //消行总数
manager->score += score[count]; //得分
if (count > 0)
manager->erasedcount[count - 1]++; //消行
//初始化方块
initTetris(manager);
//设置颜色
SetPoolColor(manager, control);
return(count > 0);
}
//向下移动方块
void moveDownTetris(Manager* manager, Control* control)
{
//记录原行的位置
int y = manager->y;
//移除当前方块
removeTetris(manager);
//向下移动
manager->y++;
//检测是否有碰撞,若有碰撞,恢复到下落前的位置插入当前方块,由于位置没变,无需设置颜色
//检测是否有消行,若有消行,重新显示游戏池 printTetrisPool
if (checkCollision(manager)) //检测碰撞
{
manager->y = y; //恢复到原行位置
insertTetris(manager); //插入当前方块,位置没变不设颜色
if (checkErasing(manager, control)) //检测到消行
{
printTetrisPool(manager, control); //显示游戏池
}
}
else //没有碰撞,插入方块,设置颜色,并显示当前方块printCurrentTetris
{
insertTetris(manager); //插入当前方块
SetPoolColor(manager, control); //设置颜色
printCurrentTetris(manager, control); //显示当前方块
}
}
//运行游戏
void runGame(Manager* manager, Control* control)
{
//clock_t代表长整型,clock_t用来保存时间的数据类型
clock_t clocklast, clocknow;
clocklast = clock(); //计时
printTetrisPool(manager, control); //显示游戏池
while (!manager->dead)
{
/* clocknow=clock(); //计时
if(clocknow-clocklast>=0.1*1000) //CLOCK_PER_SEC 1000
{
clocklast=clocknow;
moveDownTetris(manager,control);
//horzMoveTetris(manager,control);
} */
//day6
while (_kbhit()) //有按键按下
{
keydownControl(manager, control, _getch());
}
if (!control->pause) //未暂停
{
clocknow = clock(); //计时
if (clocknow - clocklast >= 0.5 * 1000) //CLOCK_PER_SEC 1000
{
clocklast = clocknow;
moveDownTetris(manager, control);
}
}
}
}
//水平移动方块
void horzMoveTetris(Manager* manager, Control* control)
{
//记录原列位置(x)
int x = manager->x;
removeTetris(manager); //移除当前方块
//左移manager->x--,右移manager->x++
control->direction == 0 ? manager->x-- : manager->x++;
//manager->x--;
if (checkCollision(manager))
{
manager->x = x; //恢复原列位置
insertTetris(manager); //放入当前方块
}
else //无碰撞
{
insertTetris(manager); //插入当前方块
SetPoolColor(manager, control); //设置颜色
printCurrentTetris(manager, control); //显示当前方块
}
}
//按键按下
void keydownControl(Manager* manager, Control* control, int key)
{
if (key == 13) //暂停/解除暂停
{
control->pause = !control->pause;
}
if (control->pause) //暂停状态,不作处理
{
return; //起到终止语句的作用
}
switch (key)
{
case 75:
case 'a':
case 'A':
case '4': //左移
control->direction = 0; //向左移动
horzMoveTetris(manager, control); //水平移动方块
break;
case 77:
case 'd':
case 'D':
case '6': //右移
control->direction = 1; //向右移动
horzMoveTetris(manager, control); //水平移动方块
break;
//day7
case 72:
case 'w':
case 'W':
case '8': //上 旋转
control->clockwise = true; //顺时针旋转
rotateTetris(manager, control); //旋转方块
break;
case '0': //反转
control->clockwise = false; //逆时针旋转
rotateTetris(manager, control); //旋转方块
break;
case 32: //直接落地 空格键
dropDownTetris(manager, control);
break;
default:
break;
}
}
//day7
//旋转方块
void rotateTetris(Manager* manager, Control* control)
{
//记录原旋转状态
int ori = manager->orientation[0];
//移除方块
removeTetris(manager);
//顺逆时针旋转状态判定,并保存旋转后的状态
manager->orientation[0] = (control->clockwise ? (ori + 1) % 4 : (ori + 3) % 4);
//检测到碰撞,若有,方块恢复到旋转前的状态,插入当前方块,若无,在当前位置放入方块并设置颜色,显示
if (checkCollision(manager)) //检测到碰撞
{
manager->orientation[0] = ori; //恢复到原旋转状态
insertTetris(manager); //放入当前方块,不设置颜色
}
else //未检测到碰撞
{
insertTetris(manager); //插入方块
SetPoolColor(manager, control); //设置颜色
printCurrentTetris(manager, control); //显示当前方块
}
}
//方块直接落地
void dropDownTetris(Manager* manager, Control* control)
{
//移走当前方块
removeTetris(manager);
//检测是否有碰撞,若有,结束下落,在碰撞上一个位置插入方块,设置颜色,检测消行,显示游戏池
for (; manager->y < ROW_END; manager->y++) //从下往下有效区域
{
if (checkCollision(manager)) //检测到碰撞
break;
}
manager->y--; //上移一行没有碰撞
insertTetris(manager); //插入当前方块
SetPoolColor(manager, control); //设置颜色
checkErasing(manager, control); //检测消行
printTetrisPool(manager, control); //显示游戏池
}
//再来一次
bool ifplayAgain()
{
int ch;
//定位设置结束文字(高亮背景色)
SetConsoleTextAttribute(output, 0xf0);
gotoxyWithFullwidth(15, 10);
printf("Game Over!");
gotoxyWithFullwidth(13, 11);
printf("按Y重玩,按N退出");
//判断是否再来一次,若按'y',返回true,重新开始,若按'n',则结束游戏
do
{
ch = _getch();
if (ch == 'Y' || ch == 'y')
return true;
else if (ch == 'N' || ch == 'n')
return false;
} while (1);
}
#endif // 1
posted on 2019-06-14 10:56 Indian_Mysore 阅读(1404) 评论(1) 编辑 收藏 举报