0xAA55 发表于 2015-8-17 02:12:44

【C语言】控制台界面的俄罗斯方块

来源:http://www.0xaa55.com/thread-1477-1-1.html
转载请注明出处。

也就是所谓“DOS窗口”的控制台程序。我写的这个是全平台的,只用了C语言的库(不过貌似有些函数好像只有微软有提供,比如_sleep这种,不过可以将其定义为void _sleep(int iTime){};来解决跨平台的兼容性问题(但是这么弄会导致这个游戏很占CPU)。


我当时写这个程序的时候我忘记了它应该叫“Tetris”而不是“Russian Blocks”(中式英语,大概可以翻译成“俄罗斯的方块”)
代码不算很复杂,一些游戏逻辑判断的函数,一些画面的逻辑判断的函数,以及整个游戏的组织函数。#include<stdint.h>
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<conio.h>
#include<string.h>
#include<signal.h>

const int8_t g_BlockTypes[]=//方块组合
{
        //格式:1个字节表示组合所需方块数,后面的字节是偏移坐标
        1,
        0,0,        //        口

        4,
        0,0,
        0,1,        //        口口
        1,0,        //        口口
        1,1,

        4,
        -1,0,
        0,0,        //        口口口口
        1,0,
        2,0,

        4,
        -1,1,
        -1,0,        //        口口口
        0,0,        //        口
        1,0,

        4,
        -1,-1,
        -1,0,        //        口
        0,0,        //        口口口
        1,0,
       
        4,
        -1,0,
        0,0,        //        口口口
        1,0,        //          口
        0,-1,

        4,
        -1,0,
        0,0,        //        口口
        0,1,        //          口口
        1,1,

        4,
        1,0,
        0,0,        //          口口
        0,1,        //        口口
        -1,1,

        0
};
//目前共8种组合
#define NbTypes 8

typedef int32_t pos_t,*pos_p;//坐标
typedef uint8_t block_t,*block_p;//方块状态

//方块缓冲区
#define BlockBufWidth        12
#define BlockBufHeight        23
block_t g_BlockBuf={0};
#define ReDirToBBuf(x,y) ((x)+(y)*BlockBufWidth)

//游戏界面显示的字符
#define BlockChar '\xB1'
#define BlankChar ' '
#define ClientAreaChar '\xDB'

//当前方块的中心位置
pos_t g_CurX,g_CurY;
uint8_t g_CurRot;//当前旋转
uint8_t g_GameOver;
uint8_t g_QuitGame;
uint16_t g_CurrentBlock;

typedef uint32_t score_t,*score_p;//用来计算分数的变量类型
#define MaxScore 999999999L
score_t g_Score=0,g_HighScore=0;

//方块视口的位置
#define VP_X 20
#define VP_Y 1
#define VP_W (BlockBufWidth*2)
#define VP_H BlockBufHeight

//“下一个方块”的提示框位置
#define NextBlockAreaX 2
#define NextBlockAreaY 2
#define NextBlockAreaW 12
#define NextBlockAreaH 6
#define NextBlockAreaR (NextBlockAreaX+NextBlockAreaW)
#define NextBlockAreaB (NextBlockAreaY+NextBlockAreaH)
#define NextBlockAreaCX (NextBlockAreaX+NextBlockAreaW/2)
#define NextBlockAreaCY (NextBlockAreaY+NextBlockAreaH/2)

#define ShowScoreAreaX 2
#define ShowScoreAreaY 9
#define ShowScoreAreaW 12
#define ShowScoreAreaH 4
#define ShowScoreAreaR (ShowScoreAreaX+ShowScoreAreaW)
#define ShowScoreAreaB (ShowScoreAreaY+ShowScoreAreaH)

#define GameOverDlgBoxAreaX 20
#define GameOverDlgBoxAreaY 4
#define GameOverDlgBoxAreaW 40
#define GameOverDlgBoxAreaH 10
#define GameOverDlgBoxAreaR (GameOverDlgBoxAreaX+GameOverDlgBoxAreaW)
#define GameOverDlgBoxAreaB (GameOverDlgBoxAreaY+GameOverDlgBoxAreaH)

#define Rot_0 0
#define Rot_90 1
#define Rot_180 2
#define Rot_270 3
uint8_t g_NextRot;//当前旋转
uint16_t g_NextBlock;

clock_t g_CurClock=0;//当前时钟计数
clock_t g_Interval=1000;//每次移动的时钟数

//“画板”
#define ScrBufWidth                80
#define ScrBufHeight        25
#define ScrBufSize (ScrBufWidth*ScrBufHeight)
char g_ScrBuf={0};//显示缓冲区
#define ReDirToScr(x,y) ((x)+(y)*ScrBufWidth)

void TranslateRotateCoord(pos_t x,pos_t y,uint8_t Rot,pos_p px,pos_p py);
void ClearBuf(char cChar);
void DrawStaticBlocks(char cBL,char cBR,char cBlank);
uint16_t GetBlockTypeData(uint16_t BlockType);
void DrawFallingComb(pos_t x,pos_t y,uint16_t BlockData,uint8_t Rot,char cBL,char cBR);

void InitGame();
void NewGame();
void MoveLeft();
void MoveRight();
void Rotate();
void FixBlock();
void NewBlock();
void FallDown();
void CheckupBlockFall();
void EraseLines();
void GameOverBox();
void FrameMove();

void InitScrBuf();
void DrawNextBlockType();
void DrawCurrentFallingBlock();
void RenderScene();
void FlushScene();

void GameMenu();
void GameLoop();

//=============================================================================
//函数:TranslateRotateCoord
//描述:翻译相对旋转坐标
//-----------------------------------------------------------------------------
void TranslateRotateCoord(pos_t x,pos_t y,uint8_t Rot,pos_p px,pos_p py)
{
        //判断是哪种旋转
        switch(Rot)
        {
        default://默认:不旋转
                *px=x;*py=y;
                break;
        case Rot_90://旋转90度,x=-y y=x
                *px=-y;*py=x;
                break;
        case Rot_180://旋转180度,x=-x y=-y
                *px=-x;*py=-y;
                break;
        case Rot_270://旋转270度,x=y y=-x
                *px=y;*py=-x;
                break;
        }
}

//=============================================================================
//函数:ClearBuf
//描述:将“画板”用cChar填充
//-----------------------------------------------------------------------------
void ClearBuf(char cChar)
{
        memset(g_ScrBuf,cChar,sizeof(g_ScrBuf));//每一行都用cChar来填
}

//=============================================================================
//函数:FillRectangle
//描述:在“画板”上填充举行
//-----------------------------------------------------------------------------
void FillRectangle(pos_t x,pos_t y,pos_t r,pos_t b,char cChar)
{
        pos_t cbLine,i;

        if(x>ScrBufWidth || y>ScrBufHeight)
                return;
        if(r>ScrBufWidth)
                r=ScrBufWidth;
        if(b>ScrBufHeight)
                b=ScrBufHeight;

        cbLine=r-x;
        i=ReDirToScr(x,y);//“画布”上的对应位置
        for(;y<b;y++)
        {
                memset(&g_ScrBuf,cChar,cbLine);//每一行都用cChar来填
                i+=ScrBufWidth;//转到下一行
        }
}

//=============================================================================
//函数:DrawStaticBlocks
//描述:在“画板”上将所有的静态方块都绘制上去(也就是画好已经落下的方块)
//-----------------------------------------------------------------------------
void DrawStaticBlocks
(
        char cBL,//方块左半边的字符
        char cBR,//方块右半边的字符
        char cBlank//没有方块时的字符
)
{
        pos_t x,y,i;

        //擦除背景
        FillRectangle(VP_X,VP_Y,VP_X+BlockBufWidth*2,VP_Y+BlockBufHeight,cBlank);

        //一行行的画方块
        for(y=i=0;y<BlockBufHeight;y++)//遍历每一行方块槽
        {
                for(x=0;x<BlockBufWidth;x++,i++)//遍历每一列方块槽
                {
                        pos_t uIndex=ReDirToScr(VP_X+x*2,VP_Y+y);//方块在“画布”对应位置
                        //方块槽每个格子相当于画布上的两个字符
                        //一个字符是长方形,两个就是正方形了
                        if(g_BlockBuf)//有方块
                        {
                                g_ScrBuf=cBL;//方块左半边的字符
                                g_ScrBuf=cBR;//方块右半边的字符
                        }
                }
        }
}

//=============================================================================
//函数:GetBlockTypeData
//描述:取得方块类型数据
//-----------------------------------------------------------------------------
uint16_t GetBlockTypeData(uint16_t BlockType)
{
        uint16_t BlockIndex=0;
        while(BlockType--)
                BlockIndex+=g_BlockTypes*2+1;
        return BlockIndex;
}

//=============================================================================
//函数:DrawFallingComb
//描述:在“画板”上绘制落下的方块组合
//-----------------------------------------------------------------------------
void DrawFallingComb
(
        pos_t x,//画布上的位置横坐标
        pos_t y,//画布上的位置纵坐标
        uint16_t BlockType,//方块种类
        uint8_t Rot,//方向
        char cBL,//方块左半边的字符
        char cBR//方块右半边的字符
)
{
        uint16_t BlockIndex=GetBlockTypeData(BlockType);
        uint8_t NbBlocks=g_BlockTypes;
        BlockIndex++;//这是坐标索引
        while(NbBlocks--)
        {
                pos_t BlockX,BlockY,uIndex;//这是转换后的相对坐标
                TranslateRotateCoord(g_BlockTypes,
                                                       g_BlockTypes,
                                                       Rot,&BlockX,&BlockY);
                //取得绝对坐标
                BlockX=BlockX*2+x;
                BlockY=BlockY+y;

                uIndex=ReDirToScr(BlockX,BlockY);//方块在“画布”对应位置
               
                g_ScrBuf=cBL;//方块左半边的字符
                g_ScrBuf=cBR;//方块右半边的字符

                BlockIndex+=2;
        }
}

//=============================================================================
//函数:DrawString
//描述:“画板”上写字
//-----------------------------------------------------------------------------
void DrawString(pos_t x,pos_t y,char*szString)
{
        size_t cbString=strlen(szString);
        memcpy(&g_ScrBuf,szString,cbString);
}

//=============================================================================
//函数:InitGame
//描述:初始化游戏
//-----------------------------------------------------------------------------
void InitGame()
{
        g_CurClock=clock();
        srand((unsigned)g_CurClock);

        InitScrBuf();

        g_HighScore=0;
}

//=============================================================================
//函数:NewGame
//描述:开始新游戏
//-----------------------------------------------------------------------------
void NewGame()
{
        g_Score=0;
        g_QuitGame=0;
        g_GameOver=0;
        g_NextRot=rand()%4;
        g_NextBlock=rand()%NbTypes;
        memset(g_BlockBuf,0,sizeof(g_BlockBuf));
        NewBlock();
        RenderScene();
        FlushScene();
}

//=============================================================================
//函数:MoveLeft
//描述:将方块往左移
//-----------------------------------------------------------------------------
void MoveLeft()
{
        uint16_t BlockIndex=GetBlockTypeData(g_CurrentBlock);
        uint8_t NbBlocks=g_BlockTypes;
        BlockIndex++;//这是坐标索引
        g_CurX--;//先左移
        while(NbBlocks--)
        {
                pos_t BlockX,BlockY;//这是转换后的相对坐标
                TranslateRotateCoord(g_BlockTypes,
                                                       g_BlockTypes,
                                                       g_CurRot,&BlockX,&BlockY);

                //左边没有空间可以移动,退出。
                if(g_CurX+BlockX<0 ||
                   g_BlockBuf)
                {
                        g_CurX++;//移回来
                        return;
                }

                BlockIndex+=2;
        }
}

//=============================================================================
//函数:MoveRight
//描述:将方块往右移
//-----------------------------------------------------------------------------
void MoveRight()
{
        uint16_t BlockIndex=GetBlockTypeData(g_CurrentBlock);
        uint8_t NbBlocks=g_BlockTypes;
        BlockIndex++;//这是坐标索引
        g_CurX++;
        while(NbBlocks--)
        {
                pos_t BlockX,BlockY;//这是转换后的相对坐标
                TranslateRotateCoord(g_BlockTypes,
                                                       g_BlockTypes,
                                                       g_CurRot,&BlockX,&BlockY);

                //左边没有空间可以移动,退出。
                if(g_CurX+BlockX>BlockBufWidth-1||
                   g_BlockBuf)
                {
                        g_CurX--;
                        return;
                }

                BlockIndex+=2;
        }
}

//=============================================================================
//函数:RotateForward
//描述:向前旋转,不带判断
//-----------------------------------------------------------------------------
static void RotateForward()
{
        switch(g_CurRot)
        {
        default:                g_CurRot=Rot_90;break;
        case Rot_90:        g_CurRot=Rot_180;break;
        case Rot_180:        g_CurRot=Rot_270;break;
        case Rot_270:        g_CurRot=Rot_0;break;
        }
}

//=============================================================================
//函数:RotateBackward
//描述:向后旋转,不带判断
//-----------------------------------------------------------------------------
static void RotateBackward()
{
        switch(g_CurRot)
        {
        default:                g_CurRot=Rot_270;break;
        case Rot_270:        g_CurRot=Rot_180;break;
        case Rot_180:        g_CurRot=Rot_90;break;
        case Rot_90:        g_CurRot=Rot_0;break;
        }
}

//=============================================================================
//函数:Rotate
//描述:旋转方块
//-----------------------------------------------------------------------------
void Rotate()
{
        uint16_t BlockIndex=GetBlockTypeData(g_CurrentBlock);
        uint8_t NbBlocks=g_BlockTypes;
        BlockIndex++;//这是坐标索引

        //先向前旋转
        RotateForward();

        while(NbBlocks--)
        {
                pos_t BlockX,BlockY;//这是转换后的相对坐标
                TranslateRotateCoord(g_BlockTypes,
                                                       g_BlockTypes,
                                                       g_CurRot,&BlockX,&BlockY);

                //如果旋转后有方块会跑出,那么就转回来。
                BlockX+=g_CurX;
                BlockY+=g_CurY;
                if(BlockX<0 || BlockY<0 ||
                   BlockX>BlockBufWidth-1 ||
                   BlockY>BlockBufHeight-1 ||
                   g_BlockBuf)
                {
                        RotateBackward();
                        return;
                }

                BlockIndex+=2;
        }
}

//=============================================================================
//函数:FixBlock
//描述:将方块固定到槽里
//-----------------------------------------------------------------------------
void FixBlock()
{
        uint16_t BlockIndex=GetBlockTypeData(g_CurrentBlock);
        uint8_t NbBlocks=g_BlockTypes;
        BlockIndex++;//这是坐标索引
        while(NbBlocks--)
        {
                pos_t BlockX,BlockY;//这是转换后的相对坐标
                TranslateRotateCoord(g_BlockTypes,
                                                       g_BlockTypes,
                                                       g_CurRot,&BlockX,&BlockY);

                g_BlockBuf=1;

                BlockIndex+=2;
        }
}

//=============================================================================
//函数:NewBlock
//描述:设置下一个方块
//-----------------------------------------------------------------------------
void NewBlock()
{
        uint16_t BlockIndex,BIStart;
        uint8_t NbBlocks,i;
       
        g_CurrentBlock=g_NextBlock;
        g_CurRot=g_NextRot;
        g_NextBlock=rand()%NbTypes;
        g_CurX=BlockBufWidth/2;
        g_CurY=0;
        g_NextRot=rand()%4;

        BlockIndex=GetBlockTypeData(g_CurrentBlock);
        NbBlocks=g_BlockTypes;
        BIStart=++BlockIndex;//这是坐标索引
        for(i=0;i<NbBlocks;i++)
        {
                pos_t BlockX,BlockY;//这是转换后的相对坐标
                TranslateRotateCoord(g_BlockTypes,
                                                       g_BlockTypes,
                                                       g_CurRot,&BlockX,&BlockY);

                //先保证方块完全进入区域
                if(g_CurY+BlockY<0)
                        g_CurY-=BlockY;

                BlockIndex+=2;
        }
        //然后判断是否有重合方块
        BlockIndex=BIStart;
        for(i=0;i<NbBlocks;i++)
        {
                pos_t BlockX,BlockY;//这是转换后的相对坐标
                TranslateRotateCoord(g_BlockTypes,
                                                       g_BlockTypes,
                                                       g_CurRot,&BlockX,&BlockY);
               
                //如果现在的位置有方块重合了
                if(g_BlockBuf)
                        g_GameOver=1;

                BlockIndex+=2;
        }
}

//=============================================================================
//函数:FallDown
//描述:坠下方块
//-----------------------------------------------------------------------------
void FallDown()
{
        g_CurY++;
}

//=============================================================================
//函数:CheckupBlockFall
//描述:检查方块状态(当前方块是否已经沉底)
//-----------------------------------------------------------------------------
void CheckupBlockFall()
{
        uint16_t BlockIndex=GetBlockTypeData(g_CurrentBlock);
        uint8_t NbBlocks=g_BlockTypes;

        BlockIndex++;//这是坐标索引
        while(NbBlocks--)
        {
                pos_t BlockX,BlockY;//这是转换后的相对坐标
                TranslateRotateCoord(g_BlockTypes,
                                                       g_BlockTypes,
                                                       g_CurRot,&BlockX,&BlockY);

                if(g_CurY+BlockY>BlockBufHeight-1 ||
                   g_BlockBuf)
                {
                        g_CurY--;
                        FixBlock();
                        NewBlock();
                }

                BlockIndex+=2;
        }
}

//=============================================================================
//函数:FallDownFixedBlocks
//描述:从第0行开始到第y行坠下固定的方块
//-----------------------------------------------------------------------------
void FallDownFixedBlocks(pos_t y)
{
        pos_t i;
        if(!y)
                return;
        i=y*BlockBufWidth;
        while(--y)
        {
                memcpy(&g_BlockBuf,&g_BlockBuf,BlockBufWidth*sizeof(block_t));
                i-=BlockBufWidth;
        }
}

//=============================================================================
//函数:EraseLines
//描述:消除填满的行
//-----------------------------------------------------------------------------
void EraseLines()
{
        pos_t y,i,LineBlockIndex;
        score_t AddScore=1;//加分(每多消除一行,多加一分)
        uint8_t CouldNotErase;

        //判断是否有已经填满的一行,并给用户统计积分
        //从最后一行开始判断
        y=BlockBufHeight-1;
        LineBlockIndex=y*BlockBufWidth;
        for(;y;y--,LineBlockIndex-=BlockBufWidth)
        {
                CouldNotErase=0;
                for(i=0;i<BlockBufWidth;i++)
                {
                        if(!g_BlockBuf)
                        {
                                CouldNotErase=1;
                                break;
                        }
                }
                if(!CouldNotErase)
                {
                        FallDownFixedBlocks(y);
                        g_Score+=AddScore++;//加分到总分里,并且同时消除的行数会增加加分量
                }
        }
        if(g_Score>g_HighScore)
                g_HighScore=g_Score;//统计最高分
}

//=============================================================================
//函数:FrameMove
//描述:判断是否在降落的时候碰到已有的方块、计算积分等
//-----------------------------------------------------------------------------
void FrameMove()
{
        char chKey;
        for(;;_sleep(1))//节省CPU的游戏循环
        {
                if(clock()-g_CurClock>=g_Interval)//超时
                {
                        //向下移动方块
                        g_CurY++;
                        g_CurClock=clock();//更新时钟
                        break;
                }
                if(_kbhit())
                {
                        chKey=_getch();
                        switch(chKey)
                        {
                        case'W':
                        case'w':
                                Rotate();
                                break;
                        case'A':
                        case'a':
                                MoveLeft();
                                break;
                        case'S':
                        case's':
                                FallDown();
                                break;
                        case'D':
                        case'd':
                                MoveRight();
                                break;
                        }
                        break;
                }
        }

        CheckupBlockFall();
        EraseLines();
}

//=============================================================================
//函数:InitScrBuf
//描述:初始化“画板”
//-----------------------------------------------------------------------------
void InitScrBuf()
{
        ClearBuf(ClientAreaChar);
}

//=============================================================================
//函数:DrawNextBlockType
//描述:在画布上绘制“下一个方块”
//-----------------------------------------------------------------------------
void DrawNextBlockType()
{
        FillRectangle(NextBlockAreaX,NextBlockAreaY,
                                  NextBlockAreaR,NextBlockAreaB,BlankChar);
        DrawString(NextBlockAreaX,NextBlockAreaY," Next Block:");
        DrawFallingComb(NextBlockAreaCX,NextBlockAreaCY,
                g_NextBlock,g_NextRot,BlockChar,BlockChar);
}

//=============================================================================
//函数:DrawTotalScore
//描述:在画布上绘制“总分”
//-----------------------------------------------------------------------------
void DrawTotalScore()
{
        char Buf;//字符串缓冲区
        FillRectangle(ShowScoreAreaX,ShowScoreAreaY,
                                  ShowScoreAreaR,ShowScoreAreaB,BlankChar);
       
        DrawString(ShowScoreAreaX,ShowScoreAreaY,"Total score:");
        sprintf(Buf,"%u",g_Score);
        DrawString(ShowScoreAreaX,ShowScoreAreaY+1,Buf);
        DrawString(ShowScoreAreaX,ShowScoreAreaY+2,"High score:");
        sprintf(Buf,"%u",g_HighScore);
        DrawString(ShowScoreAreaX,ShowScoreAreaY+3,Buf);
}

//=============================================================================
//函数:DrawCurrentFallingBlock
//描述:绘制当前正在掉落的方块
//-----------------------------------------------------------------------------
void DrawCurrentFallingBlock()
{
        DrawFallingComb(VP_X+g_CurX*2,VP_Y+g_CurY,
                g_CurrentBlock,g_CurRot,BlockChar,BlockChar);
}

//=============================================================================
//函数:RenderScene
//描述:渲染整个场景
//-----------------------------------------------------------------------------
void RenderScene()
{
        ClearBuf(ClientAreaChar);
        DrawNextBlockType();
        DrawTotalScore();
        DrawStaticBlocks(BlockChar,BlockChar,BlankChar);
        DrawCurrentFallingBlock();
}

//=============================================================================
//函数:FlushScene
//描述:将场景显示出来
//-----------------------------------------------------------------------------
void FlushScene()
{
        //强行换行
        pos_t y,i;
        for(y=0,i=0;y<ScrBufHeight-1;y++)
        {
                g_ScrBuf='\n';//然后在行末加一个换行符
                i+=ScrBufWidth;//转到下一行
        }

        fputc('\n',stdout);//插入一个新行,以让“画板”从新行输出
        fwrite(g_ScrBuf,1,ScrBufSize-1,stdout);//减去1是为了防止自动换行
}

//=============================================================================
//函数:GameMenu
//描述:游戏菜单
//-----------------------------------------------------------------------------
void GameMenu()
{
        //清屏
        system("cls");

        //显示LOGO
        fputs("\n"
"   TTTTTTTTTTEEEEEEEEEETTTTTTTTTTRRRRRRRR    IIIIIIIIII    SSSSSSSS\n"
"   TTTTTT    EE    EETTTTTT    RR    RR      II      SS      SS\n"
"         TT      EEEE      TT      RR    RR      II      SS\n"
"         TT      EEEEEE      TT      RRRRRR      II      SSSS\n"
"         TT      EEEE      TT      RRRR      II            SS\n"
"         TT      EE            TT      RR    RR      II            SS\n"
"         TT      EE    EE      TT      RR    RR      II      SS      SS\n"
"       TTTTTT    EEEEEEEEEE    TTTTTT    RRRRRRRRRRIIIIIIIIIISSSSSSSS\n"
"       \n"
"    BBBBBB    YY    YY      00000000          AAAAAAAAAAAA555555555555\n"
"    BB    BBYY    YY::00    00          AAAAAAAA55      55\n"
"    BBBBBB    YY    YY      00    00          AAAAAAAAAAAA555555555555\n"
"    BB    BB    YYYYYY      00    00XXXXAAAAAAAA      55      55\n"
"    BB    BB      YY::00    00    XX    AAAAAAAA      55      55\n"
"    BBBBBB    YYYYYY      00000000XXXXAAAAAAAA555555555555\n"
"\n"
"    http://www.0xaa55.com\n"
"\n",stdout);

        //显示最高分
        printf("    HIGH SCORE:%u\n\n",g_HighScore);

        //闪烁显示“按键开始游戏”
        for(;!g_QuitGame;_sleep(1))
        {
                if(clock()%1000 > 500)//根据时钟来判断显示字符还是抹掉字符
                        fputs("    Press 'B' to start the game.\r",stdout);
                else
                        fputs("                              \r",stdout);

                //判断按键输入
                if(_kbhit())
                {
                        char ch=_getch();
                        if(ch=='B'||ch=='b')//B键开始游戏,其它键没用。Ctrl+C退出游戏。
                        {
                                NewGame();
                                break;
                        }
                }
        }
}

//=============================================================================
//函数:GameOverBox
//描述:显示“游戏结束”框
//-----------------------------------------------------------------------------
void GameOverBox()
{
        uint8_t ShowScene=0;
        char szBuf;

        //渲染一次场景
        RenderScene();

        //画出对话框边框
        FillRectangle(GameOverDlgBoxAreaX,GameOverDlgBoxAreaY,
                GameOverDlgBoxAreaR,GameOverDlgBoxAreaB,ClientAreaChar);
        FillRectangle(GameOverDlgBoxAreaX+2,GameOverDlgBoxAreaY+1,
                GameOverDlgBoxAreaR-2,GameOverDlgBoxAreaB-1,BlankChar);

        //显示字符串
        DrawString(GameOverDlgBoxAreaX+2,GameOverDlgBoxAreaY+1,
                "Game Over");

        //显示分数
        sprintf(szBuf,"Total score:%u",g_Score);
        DrawString(GameOverDlgBoxAreaX+2,GameOverDlgBoxAreaY+3,szBuf);

        //显示最高分
        sprintf(szBuf,"High score:%u",g_HighScore);
        DrawString(GameOverDlgBoxAreaX+2,GameOverDlgBoxAreaY+5,szBuf);
               
        //闪烁提示按任意键继续,并判断按键
        for(;;_sleep(10))
        {
                if(clock()%1000<500)
                {
                        if(!ShowScene)
                        {
                                DrawString(GameOverDlgBoxAreaX+2,GameOverDlgBoxAreaY+7,
                                        "Press 'C' to continue. . .");

                                //显示已经绘制好的场景
                                FlushScene();
                                ShowScene=1;//防止重复刷屏
                        }
                }
                else
                {
                        if(ShowScene)
                        {
                                DrawString(GameOverDlgBoxAreaX+2,GameOverDlgBoxAreaY+7,
                                        "                              ");

                                //显示已经绘制好的场景
                                FlushScene();
                                ShowScene=0;//防止重复刷屏
                        }
                }

                //如果按下了键,就退出这个循环
                if(_kbhit())
                {
                        char chKey=_getch();
                        if(chKey=='C'||chKey=='c')
                                break;
                }
        }
}

//=============================================================================
//函数:GameLoop
//描述:游戏逻辑循环
//-----------------------------------------------------------------------------
void GameLoop()
{
        //游戏循环
        while(!g_GameOver)
        {
                FrameMove();
                RenderScene();
                FlushScene();
        }

        //游戏结束
        GameOverBox();
}

//=============================================================================
//函数:SigProc
//描述:信号处理程序
//-----------------------------------------------------------------------------
void SigProc(int Signal)
{
        switch(Signal)
        {
        case SIGINT:
                g_QuitGame=1;
                break;
        }
}

//=============================================================================
//函数:main
//描述:程序入口点
//-----------------------------------------------------------------------------
int main(int argc,char**Argv)
{
        signal(SIGINT,SigProc);

        system("chcp 437");
        system("mode con cols=80 lines=25");
        system("cls");

        InitGame();

        do
        {
                GameMenu();
                if(g_QuitGame)
                        break;
                GameLoop();
        }while(!g_QuitGame);
        return 0;
}BIN:
SRC:
其实名字应该叫Tetris。

账号已注销 发表于 2015-8-17 02:18:27

棒棒哒!!

Golden Blonde 发表于 2015-8-17 08:33:56

代码我要了。

佐佐哥 发表于 2015-8-17 09:25:49

先占个位置..

0x01810 发表于 2015-8-20 20:43:06

坐标设计太有才了. 这样就可以很容易实现旋转了. 大赞
页: [1]
查看完整版本: 【C语言】控制台界面的俄罗斯方块