第一个C语言项目开发------俄罗斯方块的设计与实现
这是上大学敲得第一个完整的项目,使用的开发工具是codeblock,是用纯C语言编写的。效果如下
现在把完整的整合出来
主体部分代码
#include "Tetris.h"
void gotoxyWithFullWidth(short x,short y)
{
static COORD pos;
pos.X=x*2;
pos.Y=y;
SetConsoleCursorPosition(Output,pos);
}
//显示提示信息
void printPrompting()
{
SetConsoleTextAttribute(Output,0x0B);
//gotoxyWithFullWidth(0,1);
//printf("请输入等级 1-1000:dj=");
gotoxyWithFullWidth(26,8);
printf(" 下一方块 下下一方块");
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,22);
printf("■作者 : ");
//gotoxyWithFullWidth(28,22);
// printf("★★版权所有,仿冒必究★★");
}
//==========================================================================================
//显示游戏池边界()
void printPoolBorder()
{
int x,y;
SetConsoleTextAttribute(Output,0xF0);//背景色高亮白色
for(y=4;y<26;++y)
{
gotoxyWithFullWidth(10,y-3);
SetConsoleTextAttribute(Output,0xBB);
printf("%2s","◆");
gotoxyWithFullWidth(23,y-3);
SetConsoleTextAttribute(Output,0xBB);
printf("%2s","◆");
}
for(x=10;x<=23;x++)
{
gotoxyWithFullWidth(10,22);
SetConsoleTextAttribute(Output,0xBB);
printf("%2s","◆");
}
for (y=0;y<26;++y)
{
gotoxyWithFullWidth(0,y);
SetConsoleTextAttribute(Output,0xCE);
printf ("%2s","●");
gotoxyWithFullWidth(39,y);
SetConsoleTextAttribute(Output,0xCE);
printf ("%2s","●");
}
for (x=0;x<=39;++x)
{
gotoxyWithFullWidth(x,1);
SetConsoleTextAttribute(Output,0xCE);
printf ("%2s","●");
gotoxyWithFullWidth(x,26);
SetConsoleTextAttribute(Output,0xCE);
printf ("%2s","●");
}
gotoxyWithFullWidth(10,y-3);
SetConsoleTextAttribute(Output,0xBB);
printf("%28s","");
}
//==================================================================================================
//显示得分信息
void printScore(const Manager *manager)
{
SetConsoleTextAttribute(Output,0X0B);
gotoxyWithFullWidth(2,2);
printf("■得分:%u",manager->score);
gotoxyWithFullWidth(1,6);
printf("■消行总数:%u",manager->erasedTotal);
int i;
for(i=1;i<=4;++i)
{
SetConsoleTextAttribute(Output,0X0C);
gotoxyWithFullWidth(2,8+i);
printf("□消%d:%u",i,manager->erasedCount[i-1]);
}
gotoxyWithFullWidth(1,15);
printf("■方块总数:%u",manager->tetrisTotal);
static const char * tetirsname="ITLJZSO";
for(i=0;i<7;++i)
{
SetConsoleTextAttribute(Output,0X0E);
gotoxyWithFullWidth(2,17+i);
printf("□%c形:%u",tetirsName[i],manager->tetrisCount[i]);
}
}
//===========================================================================================================
//显示下个及下下个方块的显示边框
void printNextBorder()
{
SetConsoleTextAttribute(Output,0X0F);
gotoxyWithFullWidth(26,2);
printf("┌────┬─────┐");
gotoxyWithFullWidth(26,3);
printf("│ │ │");
gotoxyWithFullWidth(26,4);
printf("│ │ │");
gotoxyWithFullWidth(26,5);
printf("│ │ │");
gotoxyWithFullWidth(26,6);
printf("│ │ │");
gotoxyWithFullWidth(26,7);
printf("└────┴─────┘");
gotoxyWithFullWidth(1,28);
}
//============================================================================
void startGame(Manager *manager,Control *control)
{
memset(manager,0,sizeof(Manager));//游戏相关数据结构体全部清0
memset(control,0,sizeof(Control));
memcpy(manager->pool,gs_uInitialTetrisPool,sizeof(unsigned int [28]));
srand((unsigned)time(NULL));//设置随机数种子
manager->type[1]=rand()%7;//初始化下一个方块的形状
manager->orientation[1]=rand()%4;//初始化下一个方块的状态
manager->type[2]=rand()%7;//初始化下下一个方块的形状
manager->orientation[2]=rand()%4;//初始化下下一个方块的状态
//memset(control,0,sizeof(Control));
initTetris(manager);
setPoolColor(manager,control);
}
//==============================================================================================
void initGame(Manager *manager,Control *control)//控制台标题,光标隐藏,游戏池初始化
{
SetConsoleTitle("俄罗斯方块");
CONSOLE_CURSOR_INFO cursorInfo={1,FALSE};
Output=GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorInfo(Output,&cursorInfo);
startGame(manager,control);
}
//================================================================================
void printNextTetirs(const Manager *manager)
{
unsigned int tetris;
tetris=TetrisTable[manager->type[1]][manager->orientation[1]];
SetConsoleTextAttribute(Output,manager->type[1]| 8);
int i;
for (i=0;i<16;++i)
{
gotoxyWithFullWidth(30-(i&3),(i>>2)+3);
((tetris>>i)&1)? printf("■"):printf("%2s","");
}
tetris=TetrisTable[manager->type[2]][manager->orientation[2]];
SetConsoleTextAttribute(Output,manager->type[2]| 8);
for (i=0;i<16;++i)
{
gotoxyWithFullWidth(35-(i&3),(i>>2)+3);
((tetris>>i)&1)? printf("■"):printf("%2s","");
}
}
//==============================================================================================
//初始化方块
void initTetris(Manager *manager)
{
unsigned int tetris;
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]];
manager->x=6;//定义方块位置
manager->y=0;
if (checkCollision(manager))
manager->dead=true;//有碰撞,游戏结束
else
{
insertTetris(manager);//没有碰撞,插入方块,
}
++manager->tetrisTotal;//方块总数增加
++manager->tetrisCount[manager->type[0]];//相应方块数增加
printNextBorder();
printScore(manager);
printNextTetirs(manager);//显示下一个,下下一个方块
//显示得分信息
}
//================================================================================
//插入方块
void insertTetris(Manager *manager)
{
unsigned int tetris;
int z;
z=12-manager->x;
tetris=TetrisTable[manager->type[0]][manager->orientation[0]];
manager->pool[manager->y+0]|=((tetris>>0x0 & 0x000F)<<z);
manager->pool[manager->y+1]|=((tetris>>0x4 & 0x000F)<<z);
manager->pool[manager->y+2]|=((tetris>>0x8 & 0x000F)<<z);
manager->pool[manager->y+3]|=((tetris>>0xC & 0x000F)<<z);
}
//===================================================================================
//显示当前方块
void printCurrentTetris(const Manager *manager,const Control *control)
{
//显示当前方块是在移动后调用的,要擦去移动前的方块,需要扩展
//向上扩展一行manager->y 向左,向右扩张 manager->x
int x,y;
y=(manager->y>4) ? (manager->y-1):4;
for(;y<26 && y<(manager->y+4);++y)
{
//x=manager->x;
x=(manager->x>2) ? (manager->x-1):2;
for(;x<14 && x<(manager->x+5);++x)
{
gotoxyWithFullWidth(x+9,y-3);
if (manager->pool[y]<<x&0x8000)
{SetConsoleTextAttribute(Output,control->color[y][x]);
printf("■");
}
else
{
SetConsoleTextAttribute(Output,0x00);
printf("%2s","");
}
}
}
}
//====================================================================================
//检测碰撞
bool checkCollision(const Manager *manager)
{
unsigned int tetris;
tetris=TetrisTable[manager->type[0]][manager->orientation[0]];
int z;
z=12-manager->x;
unsigned int dest=0;
dest|=(((manager->pool[manager->y+0]>>z)<<0x0)& 0x000F);
dest|=(((manager->pool[manager->y+1]>>z)<<0x4)& 0x00F0);
dest|=(((manager->pool[manager->y+2]>>z)<<0x8)& 0x0F00);
dest|=(((manager->pool[manager->y+3]>>z)<<0xC)& 0xF000);
return ((dest & tetris)!=0);
}
//===========================================================================================
//改变游戏池中每个方块的颜色
void setPoolColor(const Manager *manager,Control *control)
{
unsigned int tetris;
tetris=TetrisTable[manager->type[0]][manager->orientation[0]];
int i,x,y;
for(i=0;i<16;++i)
{
y=(i>>2)+manager->y;//待设置的列
if(y>26)
{
break;
}
x=manager->x+3-(i&3);
if(tetris>>i&1)
{
control->color[y][x]=(manager->type[0]|8);//设置颜色
}
}
}
//======================================================================================================
void printTetrisPool(const Manager *manager,const Control *control)
{
int x,y;
for (y=4;y<26;++y)
{
gotoxyWithFullWidth(11,y-3);
for(x=2;x<14;++x)
{
if((manager->pool[y]<<x)&0x8000)
{SetConsoleTextAttribute(Output,control->color[y][x]);
printf("■");}
else
{
SetConsoleTextAttribute(Output,0);
printf("%2s","");
}
}
}
}
//=================================================================================================================
//移除当前方块,其余保持不变
void removeTetris(Manager *manager)
{
unsigned int tetris;
tetris=TetrisTable[manager->type[0]][manager->orientation[0]];
int z;
int y;
z=12-manager->x;
manager->pool[manager->y+0]&=~(((tetris>>0x0)&0x000F)<<z);
manager->pool[manager->y+1]&=~(((tetris>>0x4)&0x000F)<<z);
manager->pool[manager->y+2]&=~(((tetris>>0x8)&0x000F)<<z);
manager->pool[manager->y+3]&=~(((tetris>>0xC)&0x000F)<<z);
}
//===============================================================================================
//向下移动方块
void moveDownTetris(Manager *manager,Control *control)
{
int y=manager->y;//原来位置 manager->y
removeTetris(manager);
//manager->y=manager->y+1;//manager-> 变化
++manager->y;
if(checkCollision(manager))//有碰撞 恢复原来位置 插入当前方块
{
manager->y=y;
insertTetris(manager);
//initTetris(manager);
if(checkFrasing(manager,control))//有消行
{
printTetrisPool(manager,control);
}
}
else//无碰撞 插入当前方块
{
insertTetris(manager);
setPoolColor(manager,control);
printCurrentTetris(manager,control);
}
}
//============================================================================================
void runGame(Manager *manager,Control *control)
{
clock_t clockLast,clockNow;
clockLast=clock();
printTetrisPool(manager,control);
while(!manager->dead)//没挂
{
while(_kbhit())
{
keydownControl(manager,control,getch());
}
if(!control->pause)
{
clockNow=clock();
if(clockNow-clockLast>=450)//
{
clockLast=clockNow;
moveDownTetris(manager,control);
}
}
}
}
//=================================================================================================
void hozeMoveTetris(Manager *manager,Control *control)
{
int x=manager->x;//记录原来X位置
removeTetris(manager);
control->direction==0 ? (--manager->x):(++manager->x);//左移或右移
if(checkCollision(manager))//检测到碰撞
{
manager->x=x;//恢复原来位置
insertTetris(manager);
//initTetris(manage);
}
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;
hozeMoveTetris(manager,control);
break;
case 77://右移
case ‘D‘:
case‘d‘:
case ‘6‘:
control->direction=1;
hozeMoveTetris(manager,control);
break;
case 80: //下移
case ‘S‘:
case‘s‘ :
case ‘2‘:
moveDownTetris(manager,control);
break;
case 72://顺时针转
case ‘W‘:
case ‘w‘:
case ‘8‘:
control->chockwise=true;
rotateTetris(manager,control);
break;
case ‘0‘://逆时针转
control->chockwise=false;
rotateTetris(manager,control);
break;
case ‘ ‘://直接落地
dropDownTetris(manager,control);
break;
default:
break;
}
}
//========================================================================================
//旋转方块
void rotateTetris(Manager *manager,Control *control)
{
int ori=manager->orientation[0];//记录当前方块状态
removeTetris(manager) ;//移走当前方块
manager->orientation[0]=(control->chockwise)?(ori+1)&3:(ori+3)&3;//顺指针改变状态
if(checkCollision(manager))//有碰撞
{
manager->orientation[0]=ori;//恢复原来状态
insertTetris(manager);//插入当前方块
}
else//无碰撞 放入当前方块
{
insertTetris(manager);
setPoolColor(manager,control);//设置颜色,显示当前方块
printCurrentTetris(manager,control);
}
}
//==============================================================
//消行检测
bool checkFrasing(Manager *manager,Control *control)
{
static const unsigned int score[5]={0,1,3,6,9};//定义数组存分数 消0,1,2,3,4
int count=0;//定义变量用于存很消行数 0
int y=manager->y+3;//从下往上检测 y=manager->y+3
do
{
if(y<26 && manager->pool[y]==0xFFFFU)//游戏池底部不能消且一行的值全为1
{
count++;//增加消行数
memmove(manager->pool+1,manager->pool,sizeof(unsigned int)*y);
memmove(control->color[1],control->color[0],sizeof(int[16])*y);//游戏池整体下移一行,颜色下移一行
gotoxyWithFullWidth(15,18);
SetConsoleTextAttribute(Output,0xF0);
printf ("GOOD");
}
else
{
--y;
}
} while(y>=manager->y); //循环最多4次
manager->erasedTotal+=count;//消行总数增加
manager->score+=score[count];//得分增加
if(count>0)
{
++manager->erasedCount[count-1];//相应消行数增加
}
initTetris(manager);//初始化方块
setPoolColor(manager,control);//设置游戏池颜色
return (count>0);
}
//=======================================================
//直接落地
void dropDownTetris(Manager *manager,Control *control)
{
int y;
removeTetris(manager);//移走当前方块
for(;manager->y<26;++manager->y)
{
if(checkCollision(manager))
{
break;
}
}
//循环 y<26 ++manager->y
--manager->y;//--manager->y 恢复位置
insertTetris(manager);//插入当前方块
setPoolColor(manager,control);//设置颜色
checkFrasing(manager,control); //检测消行
printTetrisPool(manager,control);//显示游戏池
}
//==============================================================
//再来一次
bool ifPlayAgain()
{
int Y,y ,n, N;
int ch; //定义整形变量,用于接受键盘输入的字符
SetConsoleTextAttribute(Output,0xF0); //设置颜色, 前景色为黑色,背景色白色
gotoxyWithFullWidth(15,10); //设置位置15,10
printf("Game over"); //打印游戏结束
gotoxyWithFullWidth(13,11);//设置位置13,11
printf("按Y重玩,按N退出");//打印按y重玩, 按n退出
do{ //do
ch=_getch() ; //变量=从键盘接受字符
if(ch==‘y‘ ||ch== ‘Y‘)
{
return true;
} //判断是yY return true
else if(ch==‘n‘||ch==‘N‘)
{
return false;
} //判断是nN return false;
}while(1);
} //while(1)
//=============================================================
//游戏等级
//void youxidengji()
//{
// int a;
// SetConsoleTextAttribute(output,0xF0);
// gotoxyWithFullWidth(16,11);
// printf("请选择等级123");
//}
Tetris.h文件
#ifndef TETRIS_H_INCLUDED
#define TETRIS_H_INCLUDED
#include <stdio.h>//标准输入输出头文件
#include <string.h>//标准字符串头文件
#include<stdlib.h>//标准库头文件
#include <time.h>//日期和时间头文件
#include <conio.h>//控制台输入输出头文件
#include<windows.h>//windows控制台头文件
#include<stdbool.h>//标准库尔函数头文件
//定义7种的方块的4种状态
static const unsigned int TetrisTable[7][4]=
{
//==================================
//正常状态
{0x00F0,0x2222,0x00F0,0x2222},//I形方块的4个状态
{0x7200,0x8C80,0x004E,0x0131},//T形方块的4个状态
{0x6440,0x08E0,0x0226,0x0710},//L形方块的4个状态
{0x4460,0x02E0,0x0622,0x0740},//J形方块的4个状态
{0x3600,0x8C40,0x006C,0x0231},//Z形方块的4个状态
{0x2640,0x0C60,0x0264,0x0630},//S形方块的4个状态
{0x0660,0x0660,0x0660,0x0660},//O形方块的4个状态
//==================================
//全I形
{0x0F00,0x4444,0x00F0,0x2222},
{0x0F00,0x4444,0x00F0,0x2222},
{0x0F00,0x4444,0x00F0,0x2222},
{0x0F00,0x4444,0x00F0,0x2222},
{0x0F00,0x4444,0x00F0,0x2222},
{0x0F00,0x4444,0x00F0,0x2222},
{0x0F00,0x4444,0x00F0,0x2222},
//====================================
//全O形
{0x0660,0x0660,0x0660,0x0660},
{0x0660,0x0660,0x0660,0x0660},
{0x0660,0x0660,0x0660,0x0660},
{0x0660,0x0660,0x0660,0x0660},
{0x0660,0x0660,0x0660,0x0660},
{0x0660,0x0660,0x0660,0x0660},
{0x0660,0x0660,0x0660,0x0660},
{0x0660,0x0660,0x0660,0x0660},
};
//初始化游戏池
//28行每行16位,前26行每行16位,每行前2位,最后两位均为1,其余为0,用于检测碰撞
//最后2行全部为1,用于检测碰撞
//当某一行为0xFFFF时,该行已满,可以消行
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,
};
typedef struct TetrisManager //这个结构体存储游戏相关数据
{
unsigned int pool[28];//记录游戏池,28行,每行16位
int x;//记录方块的x坐标,左上角坐标
int y;//记录方块的y坐标
int type[3];//当前,下一个,下下以一个方块的形状
int orientation[3];//当前,下一个,下下一个的状态
unsigned int score;//得分
unsigned int erasedTotal;//消行总数
unsigned int erasedCount[4];//消1,2,3,4的数目
unsigned int tetrisTotal;//方块总数
unsigned int tetrisCount [7];//7种方块的数目
bool dead;//游戏结束
}Manager ;
typedef struct TetrisControl//这个结构体存储控制相关数据
{
bool pause;//暂停
bool chockwise;//旋转方向 顺时针位true
int direction;//移动方向,0;向左移动;1; 向右移动
int color[28][16];//游戏池中每个点的颜色
}Control;
HANDLE Output;
void gotoxyWithFullWidth(short x,short y);
void printPrompting();//显示提示信息
void printPoolBorder();//显示游戏池边界
void printScore();//显示得分信息
void printNextBorder();//显示下一个,下下一个边框
void startGame(Manager *manager,Control *Control);
void initGame (Manager *manager,Control *control);
void printNextTetirs(const Manager *manager);//显示下一个下下一个方块
void initTetris(Manager *manager);//初始化当前方块,下一个,下下一个
void insertTetris(Manager *manager);//插入当前方块
void printCurrentTetris(const Manager *manager,const Control *Control);//显示当前方块
bool checkCollision(const Manager *manager);//碰撞检测
void setPoolColor(const Manager *manager,Control *control);//设置游戏池当前方块颜色
void printTetrisPool(const Manager *manager,const Control *control);
void removeTetris(Manager *manager);//移除当前方块,游戏池中有方块的清零
void moveDownTetris(Manager *manager,Control *control);
void runGame(Manager *manager,Control *control);//运行游戏
void hozeMoveTetris(Manager *manager,Control *control);//水平移动方块
void keydownControl(Manager *manager,Control *control,int key);//按键控制
void rotateTetris(Manager *manager,Control *control);//旋转方块
bool checkFrasing(Manager *manager,Control *control);//消行检测
void dropDownTetris(Manager *manager,Control *control);//方块直接落地
bool ifPlayAgain();//再来一次
//void youxidengji();//游戏等级
#endif // TETRIS_H_INCLUDED
主函数
#include <stdio.h>
#include <stdlib.h>
#include "Tetris.h"
int main()
{
Manager manager;
Control control;
//printNextBorder();
initGame(&manager,&control);
//initTetris(&manager);
printPoolBorder();
printPrompting();
do
{
//printNextBorder();
//printNextTetirs(&manager);
printPrompting();
printPoolBorder();
//setPoolColor(&manager,&control);
//printScore(&manager);
//printCurrentTetris(&manager,&control);
//insertTetris(&manager);
//printTetrisPool(&manager,&control);
//moveDownTetris(&manager,&control);
runGame(&manager,&control);
if(ifPlayAgain())//判断重玩函数是真,假
{
SetConsoleTextAttribute(Output,0x07);//真值,重玩 颜色设置为0x07
system("cls");//system("cls")清屏
startGame(&manager,&control);//重新开始游戏 startGame
}
else
{
break;
}//假值 break
//
} while(1);
gotoxyWithFullWidth(0,0);
CloseHandle(Output);
return 0;
}