




#ifndef _DAY7_H #define _DAY7_H #include
#include
#include
#include
//控制台输入输出函数getch通过键盘进行的操作 //游戏区域位置设计 #define COL_BEGIN 2 #define COL_END 14 #define ROW_BEGIN 4 #define ROW_END 26 HANDLE Output;//控制台输出句柄 //存储游戏相关数据的结构体 typedef struct TetrisManager//俄罗斯管理 {
unsigned int pool[28];//游戏池 int x;//当前方块的x坐标,左上角坐标 int y;// int type[3];//当前,下一个,下下一个方块的类型 int orientation[3];//当前,下一个,下下一个方块的旋转状态 //左边栏 unsigned score;//得分 unsigned erasedTotal;//消行总数 unsigned erasedCount[4];//消几行数 unsigned tetrisTotal;//目前出现方块总数 unsigned tetrisCount[7];//目前出现各种方块数 bool dead;//挂 }Manager;//结构体别名 //构造存储游戏控制相关数据的结构体 typedef struct TetrisControl {
bool pause;//暂停 bool clockwise;//旋转方向;顺时针方向为ture int direction;//移动方向:0向左移动 1向右移动 //游戏池内每格的颜色 //此版本是彩色的,仅用游戏池数据无法存储颜色 int color[28][16]; }Control;//Control是结构体别名 //初始状态的游戏池 //每个元素表示游戏池的一行 //两端各置两个1,底部两行全部为1,便于进行碰撞 //这样一来游戏池的宽度为12列 共16列 //当某个元素为OXFFFF时,说明该行已经填满 //顶部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 //C003 1100 0000 0000 0011 }; //7种方块的4种旋转状态(4位一行) static const unsigned int TetrisTable[7][4]= {
{
0x00f0, 0x2222,0x00f0,0x2222 },//I {
0x0072, 0x0262,0x0270,0x0232 },//T {
0x0223, 0x0074,0x0622,0x0170 },//L {
0x0226, 0x0470,0x0322,0x0071 },//J {
0x0063, 0x0264,0x0063,0x0264 },//Z {
0x006c, 0x0462,0x006c,0x0462 },//S {
0x0660, 0x0660,0x0660,0x0660 },//O }; //函数声明 void printPoolBorder();//显示游戏池边界 void gotoxyWithFullwidth(short x,short y);//全角显示鼠标定位函数 void printPrompting();//显示按键提示信息 void printScore(const Manager *manager); void intiGame(Manager* manager,Control*control);//初始化游戏 void startGame(Manager *manager,Control *control); void printNextTetris(const Manager *manager); void printTetrisPool(const Manager *manager,Control *control);//显示游戏池 void initTetris(Manager *manager);//初始化方块 void insertTetris(Manager *manager);//插入方块 bool checkCollision(const Manager *manager);//检测碰撞 void setPoolColor(const Manager *manager,Control *control); void printCurrentTetris(const Manager *manager,const Control *control); void removeTetris(Manager *manager);//移除当前方块 void moveDownTetris(Manager *manager, Control *control);//向下移动方块 void runGame(Manager *manager, Control *control);//运行游戏 void horzMoveTetris(Manager *manager, Control *control);//水平移动方块 void keydownControl(Manager *manager, Control *control,int key);//按键按下控制 void rotateTetris(Manager *manager, Control *control);//旋转方块 void dropDownTetris(Manager *manager, Control *control);//方块直接落地 bool ifPlayAgain();//是否重玩 bool checkErasing(Manager *manager, Control *control);//消行检测 #endif // _DAY7_H
#include
#include
#include"day7.h" int main() {
Manager manager; Control control; intiGame(&manager,&control);//初始化游戏 do {
printPrompting();//按键提示信息 printPoolBorder();//游戏池 runGame(&manager,&control); if(ifPlayAgain()) {
SetConsoleTextAttribute(Output,0x07); system("cls") ;//清屏 startGame(&manager,&control);//从新开始游戏 } else break; }while(1); intiGame(&manager,&control);//初始化游戏 CloseHandle(Output); return 0; } //初始化游戏 void intiGame(Manager* manager,Control*control) {
Output=GetStdHandle(STD_OUTPUT_HANDLE); //定义光标隐藏变量并初始化 CONSOLE_CURSOR_INFO info; info.bVisible=FALSE;//FAlse为光标隐藏 info.dwSize=1;//光标亮度为1-100 //设置光标隐藏 SetConsoleCursorInfo(Output,&info);//提取光标地址 SetConsoleTitle("俄罗斯方块");//控制台句柄 startGame(manager,control);//调用游戏 } //游戏池 void printPoolBorder() {
int y; SetConsoleTextAttribute(Output,0xf0); for(y=4;y<26;y++) {
//两条纵线 gotoxyWithFullwidth(10,y-3);//鼠标定位 printf("%2s"," "); gotoxyWithFullwidth(23,y-3);//鼠标定位 printf("%2s"," "); } gotoxyWithFullwidth(10,y-3);//一条横线 printf("%28s"," "); } //显示全角定位 void gotoxyWithFullwidth(short x,short y) {
static COORD cd; cd.X= x*2;//移动1个坐标乘以2,改变2个像素点的 距离 cd.Y=y; //移动光标到指定位置 SetConsoleCursorPosition(Output,cd);//输出句柄 } //按键提示信息 void printPrompting() {
//设置文字颜色,高亮 SetConsoleTextAttribute(Output,0x0b); //设置文字位置 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(26,23); printf("▉By:briup"); } //显示得分信息 void printScore(const Manager *manager) {
static const char *tetrisName="ITLJZSO"; int i; //设置文字颜色 文字颜色 高亮红+绿=黄色 SetConsoleTextAttribute(Output,0x0E); //得分 gotoxyWithFullwidth(2,2); printf("█得分:%u",manager->score); //消行总数 gotoxyWithFullwidth(1,6); printf("█消行总数:%u",manager->erasedTotal); //一次消1234行数纪录 for(i=0;i<4;i++) {
gotoxyWithFullwidth(2,8+i); printf("□消%d:%u",i+1,manager->erasedCount[i]); } //目前出现的方块总数 gotoxyWithFullwidth(1,15); printf("█方块总数:%u",manager->tetrisTotal); //目前出现的ITLJZSO类型的方块数纪录 for(i=0;i<7;i++) {
gotoxyWithFullwidth(2,17+i); printf("□%c形:%u",tetrisName[i],manager->tetrisCount[i]); } } //开始游戏 void startGame(Manager *manager,Control *control) {
/*主要是初始化相关游戏值*/ //初始化结构体内存空间 memset(manager,0,sizeof(Manager)); //初始化游戏池 memcpy(manager->pool,gs_uInitialTetrisPool,sizeof(unsigned [28]) ); //使用时间作为种子参数 srand((unsigned)time(NULL)); //初始化下一个方块 manager->type[1]=rand()%7; manager->orientation[1]=rand()%4; manager->type[2]=rand()%7; manager->orientation[2]=rand()%3; memset(control,0,sizeof(Control)); //初始化方块 initTetris(manager);//给下一个方块 setPoolColor(manager,control);//设置颜色 } //显示下一个,下下一个 void printNextTetris(const Manager *manager) {
int i; unsigned int tetris;//存储下一个,下下一个类型 //设置边框 SetConsoleTextAttribute(Output,0X0f);//高亮白色 gotoxyWithFullwidth(26,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]]; SetConsoleTextAttribute(Output,manager->type[1]|8);//前景高亮 for(i=0;i<16;i++) {
//x初始位置是27 (i&3)0—15的值为 0123 0123 0123 0123 //y初始位置是2 (i>>2)右移两位0—15的值为00003 gotoxyWithFullwidth((i&3)+27,(i>>2)+2); if((tetris>>i)&1) printf("■"); else printf("%2s",""); } tetris=TetrisTable[manager->type[2]][manager->orientation[2]]; SetConsoleTextAttribute(Output,8); for(i=0;i<16;i++) {
//x初始位置是33 (i&3)0—15的值为 0123 0123 0123 0123 //y初始位置是2 (i>>2)右移两位0—15的值为00003 gotoxyWithFullwidth((i&3)+33,(i>>2)+2); if((tetris>>i)&1) printf("■"); else printf("%2s",""); } } #define gotoxyInPool(x,y) gotoxyWithFullwidth(x+9,y-3) //显示游戏池里的方块 void printTetrisPool(const Manager *manager,Control *control) {
int x,y; for(y=ROW_BEGIN;y<ROW_END;y++)//4,26 {
gotoxyInPool(2,y);//2+9=11.游戏池中光标定位 // gotoxyWithFullwidth(11,y-3); //定点到游戏池中的方格2 14 for(x=COL_BEGIN;x<COL_END;x++) {
if((manager->pool[y]>>x) &1)//1100 0000 0000 0011 >>2 //用相应的颜色,显示一个实心的方块 {
SetConsoleTextAttribute(Output,control->color[y][x]); //control->color[y][x] 是一个数 //一个方块如0X00f0 只有0和1组成 若想有特定的颜色 就要扩展成4*4的数组 //有1的地方 就赋值为特定的数 也就是特定的颜色 //也就是说这xy坐标所确定的地方 不是1 而是一个特定的颜色数manager->type[0]|8设置高亮 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 &0x000F)//俄罗斯方块最先显示最下面一行 manager->y=0; else manager->y=(tetris &0x00FF)?1:2; manager->x=6;//设置当前方块x坐标 // manager->y=4;//设置当前方块y坐标 实际出现游戏池内方块出现坐标6,1 if(checkCollision(manager)) //检测碰撞 manager->dead=true;//标记游戏结束 else insertTetris(manager); //将当前方块加入游戏池 manager->tetrisTotal++;//方块总数加起来 manager->tetrisCount[manager->type[0]]++;//相应方块数 printNextTetris(manager);//显示下一个和下下一个方块 printScore(manager);//显示得分信息 } //插入方块 void insertTetris(Manager *manager) {
//插入当前方块 unsigned int tetris;//16位 tetris = TetrisTable[manager->type[0]][manager->orientation[0]]; //(tetris >>0x0)&0x0f)当前方块每四位取出,<< manager->x 左移6位 再与0xc003或,最终移到游戏池中央 manager->pool[manager->y+0]|=(((tetris >>0x0)&0x0f)<< manager->x); manager->pool[manager->y+1]|=(((tetris>>0x4)&0x0f)<<manager->x); manager->pool[manager->y+2]|=(((tetris >>0x8)&0x0f)<< manager->x); manager->pool[manager->y+3]|=(((tetris>>0xc)&0x0f)<<manager->x); } //设置游戏池中方块的颜色 void setPoolColor(const Manager *manager,Control *control) {
//只做设置颜色,不需要清除 //当移动方块或给一个方块时候在调用 int x,y,i; unsigned int tetris; tetris=TetrisTable[manager->type[0]][manager->orientation[0]]; for(i=0;i<16;i++) {
y=(i>>2)+manager->y;//0000 1111 2222 3333 x=(i &3)+manager->x;//0123 0123 0123 0123 x=6 游戏池中间值 if(y>ROW_END)//26 break; if((tetris>>i) &1) //用相应的颜色,显示一个实心的方块 control->color[y][x]=(manager->type[0]|8);//设置当前方块颜色 //有四行0 1 2 3 每行有四列0123 } } //显示当前方块(左右下移动) void printCurrentTetris(const Manager *manager,const Control *control) {
//显示当前的方块是移动后调用的,必须为擦除移动前的方块,需要扩展显示区域 int x,y; y=(manager->y>ROW_BEGIN)?manager->y-1:ROW_BEGIN;//下移时向上扩展一格 for(;y<ROW_END&&y<manager->y+4;y++) {
x=(manager->x>COL_BEGIN)?(manager->x-1):COL_BEGIN;//右移向左扩展一格 for(;x<COL_END&&x<manager->x+5;x++)//向右扩展一格 {
gotoxyInPool(x,y); //gotoxyWithFullwidth(2+9,y-3)相对点控制台 //定点到游戏池内的方格 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 dest=0;//16位 //获取当前方块 unsigned int tetris; tetris=TetrisTable[manager->type[0]][manager->orientation[0]]; //获取当前方块在游戏池中的区域 //游戏池坐标x,y处小方格信息,由低到高放在16位 dest |=((((manager->pool[manager->y+0])>>manager->x)<<0x0)&0x000f);//取出游戏池中区域低4位, //如果碰撞到之前保存在游戏池中的方块,则为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); return ((dest & tetris) !=0); } //移除当前方块 void removeTetris(Manager *manager) {
unsigned int tetris; 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 moveDownTetris(Manager *manager, Control *control) {
int y; y=manager->y; //记录原行位置 removeTetris(manager);//移走当前方块 ++manager->y;//向下移动 if(checkCollision(manager))//检测到碰撞 {
manager->y=y;//恢复原行位置 insertTetris(manager);//放入当前方块,由于位置没变不需要设置颜色 if(checkErasing(manager,control)) //检测到消行 printTetrisPool(manager,control);//刷新游戏池 } else {
insertTetris(manager);//放入当前方块 setPoolColor(manager,control);//设置颜色 printCurrentTetris(manager,control);//显示当前方块,扩展 printTetrisPool(manager,control);//显示游戏池 } } //运行游戏 void runGame(Manager *manager, Control *control) {
clock_t clocknow,clocklast;//clock_t长整型 clocklast=clock();//clock()返回CPU启动到调用clock()时的硬件滴答数 while(!manager->dead) {
while(_kbhit())//有键按下 {
keydownControl(manager,control,getch());//处理按键 } if(!control->pause)//未暂停 {
clocknow=clock(); if(clocknow-clocklast>0.45*CLOCKS_PER_SEC)//*1000 {
moveDownTetris(manager,control); clocklast=clocknow; } } } } //水平移动方块 void horzMoveTetris(Manager *manager, Control *control) {
int x=manager->x;//记录原列位置 removeTetris(manager);//移走当前方块 if(control->direction==0)//左移为0,右移为1 --manager->x; //左移 else ++manager->x; //右移 if(checkCollision(manager)) {
manager->x=x;//恢复为原列位置 insertTetris(manager);//还是原行的位置颜色不用设置 } else {
insertTetris(manager);//放入当前方块 setPoolColor(manager,control);//设置颜色 printCurrentTetris(manager,control);//显示当前方块,扩展 } } //旋转方块 void rotateTetris(Manager *manager, Control *control) {
int ori=manager->orientation[0];//记录旋转状态 removeTetris(manager);//移走当前方块 //顺/逆时针旋转 if(control->clockwise) manager->orientation[0]=(ori+1)&3;//顺时针 else manager->orientation[0]=(ori+3)&3;//逆时针 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)) {
//跳出for循环函数 break; } } // 由于检测到碰撞,需上移一格没有碰撞的方块 manager->y--; //上移一格 insertTetris(manager); // 放入当前方块 函数调用实现 setPoolColor(manager,control); // 设置颜色 函数调用实现 checkErasing(manager,control); // 检测消行 函数调用实现 printTetrisPool(manager,control); // 显示游戏池 函数调用实现 } // 重玩一次 bool ifPlayAgain() {
//设置按键接收变量 int ch; //设置游戏结束提示信息颜色SetConsoleTextAttribute(); SetConsoleTextAttribute(Output,0xf0); //背景颜色 //移动到指定位置,打印文字(15,10); gotoxyWithFullwidth(15, 10); printf("游戏结束"); gotoxyWithFullwidth(13,11); printf("按Y重玩,按N退出"); do {
//按键接收字符 getch()实现 ch=getch(); //判断按键键值,y 返回true if(ch=='y'||ch=='Y') {
return true; } //判断按键键值,n 返回false else if(ch=='n'||ch=='N') {
return false; } } while (1); } //按键按下控制 void keydownControl(Manager *manager, Control *control,int key) {
if (key == 13) // 暂停/解除暂停 {
control->pause = !control->pause; } if (control->pause) // 暂停状态,不作处理 {
return;//起到终止语句的作用 } switch(key) {
case 's': case 'S': case '2': case 80: // 下 扫描键 moveDownTetris(manager, control); // 向下移动方块 break; case 'A': case 'a': case '4': case 75 : //左移 control->direction=0; horzMoveTetris(manager, control); break; case 'D': case 'd': case '6': case 77 ://右移 control->direction=1; horzMoveTetris(manager, control); break; case 'W': case 'w': case '8': case 72 ://上按键,顺时针 control->clockwise=true; rotateTetris(manager,control); break; case '0' ://逆时针 control->clockwise=false; rotateTetris(manager,control); break; //直接落地 ' ' case ' ': // 直接落地 // 调用直接落地函数 dropDownTetris(manager, control); //返回 break; default: break; } } //消行检测 bool checkErasing(Manager *manager, Control *control) {
static const unsigned scores[5]={
0,10,30,90,100};//消行总分 int count=0; //从下往上检测 int y=manager->y+3; //有效区域内且一行已被填满 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+=scores[count];//得分信息 if(count>0) {
manager->erasedCount[count-1]++;//消行 } initTetris(manager);//初始化方块 setPoolColor(manager,control);//设置颜色 if(count>0) return true; else return false; }
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/218832.html原文链接:https://javaforall.net
