C语言俄罗斯方块

注: 本篇是在明日学院的俄罗斯方块代码的基础上优化而成的!

游戏介绍

顾名思义,俄罗斯方块自然是俄罗斯人发明的。这人叫阿列克谢·帕基特诺夫(Алексей Пажитнов 英文:Alexey Pazhitnov)。俄罗斯方块原名是俄语Тетрис(英语是Tetris),这个名字来源于希腊语tetra,意思是“四”,而游戏的作者最喜欢网球(tennis)。于是,他把两个词tetra和tennis合而为一,命名为Tetris,这也就是俄罗斯方块名字的由来。

游戏规则

游戏规则:各式各样的俄罗斯方块(本篇17种样式),由小方块组成的不同形状的板块陆续从屏幕上方落下来,玩家通过调整板块的位置和方向和形状,使它们在屏幕底部拼出完整的一条或几条。这些完整的横条会随即消失,给新落下来的板块腾出空间,与此同时,玩家得到分数奖励。没有被消除掉的方块不断堆积起来,一旦堆到屏幕顶端,玩家便告输,游戏结束。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>            //标准输入输出函数库(printf、scanf)
#include <windows.h>          //控制DOS界面(获取控制台上坐标位置、设置字体颜色)
#include <conio.h>            //接收键盘输入输出(_kbhit()、_getch())
#include <time.h>             //用于获得随机数
#include <Aclapi.h>
#include <atlsecurity.h>

#define MY_BUFSIZE 1024    //控制台窗口标题的缓冲区大小
#define FrameX 13             //游戏窗口左上角的X轴坐标为13
#define FrameY 3              //游戏窗口左上角的Y轴坐标为3
#define Frame_height  20      //游戏窗口的高度为20
#define Frame_width  18       //游戏窗口的宽度为18

int i, j, Temp, Temp1, Temp2;     //temp,temp1,temp2用于记住和转换方块变量的值

int a[80][80] = { 0 };          //标记游戏屏幕的图案:2,1,0分别表示该位置为游戏边框、方块、无图案;初始化为无图案

int b[4];                          //标记4个"口"方块:1表示有方块,0表示无方块
typedef struct                     //声明俄罗斯方块的结构体
{
    int x;                         //中心方块的x轴坐标
    int y;                         //中心方块的y轴坐标
    int flag;                      //标记方块类型的序号
    int next;                      //下一个俄罗斯方块类型的序号
    int speed;                    //俄罗斯方块移动的速度
    int number;                   //产生俄罗斯方块的个数
    int score;                    //游戏的分数
    int level;                    //游戏的等级
}xin; 
HANDLE hOut;                      //控制台句柄
HWND GetConsoleHwnd();             //获取窗口句柄    
void gotoxy(int x, int y);                  //光标移到指定位置
void DrwaGameframe();                       //绘制游戏边框
void Flag(xin*);                            //随机产生方块类型的序号
void MakeTetris(xin*);                      //制作俄罗斯方块
void PrintTetris(xin*);                     //打印俄罗斯方块
void CleanTetris(xin*);                     //清除俄罗斯方块的痕迹
int  ifMove(xin*);                          //判断是否能移动,返回值为1,能移动,否则,不能移动
void Del_Fullline(xin*);                    //判断是否满行,并删除满行的俄罗斯方块
void Gameplay();                            //开始游戏
void regulation();                          //游戏规则
void explation();                           //按键说明
void welcom();                              //欢迎界面
void Replay(xin* tetris);                   //重新开始游戏
void title();                               //欢迎界面上方的标题
void flower();                              //欢迎界面上的字符装饰花
void close();                               //关闭游戏

/**
 * 文字颜色函数
 */
int color(int c)
{
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), c);        //更改文字颜色
    return 0;
}

/**
 * 获取屏幕光标位置
 */
void gotoxy(int x, int y)
{
    COORD pos;
    pos.X = x;      //横坐标
    pos.Y = y;      //纵坐标
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}

/**
 * 欢迎界面上方的标题
 */
void title()
{
    color(13);                        //亮白色
    gotoxy(26, 2);
    printf("趣  味  俄  罗  斯  方  块\n");    //输出标题
    color(11);                         //亮蓝色
    gotoxy(18, 5);
    printf("■");                        //■
    gotoxy(18, 6);                      //■■
    printf("■■");                       //■
    gotoxy(18, 7);
    printf("■");
    color(14);                             //黄色
    gotoxy(26, 6);
    printf("■■");                     //■■
    gotoxy(28, 7);                    //  ■■
    printf("■■");
    color(10);                        //绿色
    gotoxy(36, 6);                    //■■
    printf("■■");                     //■■
    gotoxy(36, 7);
    printf("■■");
    color(13);                         //粉色
    gotoxy(45, 4);
    printf("■");                      //■
    gotoxy(45, 5);                    //■
    printf("■");                      //■
    gotoxy(45, 6);                    //■
    printf("■");
    gotoxy(45, 7);
    printf("■");
    color(12);                         //亮红色
    gotoxy(56, 6);
    printf("■");                     //    ■
    gotoxy(52, 7);                     //■■■
    printf("■■■");
}
/**
 * 主  函  数
 */

int main()
{
    //设置窗口
    system("mode con cols=90 lines=30");
    SetWindowLongPtr(GetConsoleHwnd(), GWL_STYLE, WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX);
    title();            //欢迎界面上的标题
    flower();           
    welcom();
}

/**
 * 获取当前窗口句柄
 */
HWND GetConsoleHwnd()            //获取窗口句柄      
{

    HWND hwndFound;                      //最后获得的句柄 
    WCHAR pszNewWindowTitle[MY_BUFSIZE]; //窗口标题

    WCHAR pszOldWindowTitle[MY_BUFSIZE]; //旧的句柄 


    //获取当前窗口标题

    GetConsoleTitle(pszOldWindowTitle, MY_BUFSIZE);

    //设置唯一窗口名子。 

    char szStr[MY_BUFSIZE];

    sprintf(szStr, "%d%d", GetTickCount(), GetCurrentProcessId());   //因为为了兼容下面的MessagrBox这里用的

    memset(pszNewWindowTitle, 0, sizeof(pszNewWindowTitle));
    MultiByteToWideChar(CP_ACP, 0, szStr, strlen(szStr) + 1, pszNewWindowTitle, sizeof(pszNewWindowTitle) / sizeof(pszNewWindowTitle[0]));

    //更改当前窗口标题 
    SetConsoleTitle(pszNewWindowTitle);

    //确保窗口标题已更新 
    Sleep(40);

    //查找新窗口标题
    hwndFound = FindWindow(NULL, pszNewWindowTitle);

    //还原原始窗口标题
    SetConsoleTitle(pszOldWindowTitle);

    return(hwndFound);        //返回句柄
}


/**
 * 绘制字符花
 */
void flower()
{
    gotoxy(66, 11);       //确定屏幕上要输出的位置
    color(12);            //设置颜色
    printf("(_)");        //红花上边花瓣
    gotoxy(64, 12);
    printf("(_)");        //红花左边花瓣
    gotoxy(68, 12);
    printf("(_)");        //红花右边花瓣
    gotoxy(66, 13);
    printf("(_)");        //红花下边花瓣
    gotoxy(67, 12);       //红花花蕊
    color(6);
    printf("@");
    gotoxy(72, 10);
    color(13);
    printf("(_)");      //粉花左边花瓣
    gotoxy(76, 10);
    printf("(_)");      //粉花右边花瓣
    gotoxy(74, 9);
    printf("(_)");      //粉花上边花瓣
    gotoxy(74, 11);
    printf("(_)");      //粉花下边花瓣
    gotoxy(75, 10);
    color(6);
    printf("@");        //粉花花蕊
    gotoxy(71, 12);
    printf("|");          //两朵花之间的连接
    gotoxy(72, 11);
    printf("/");          //两朵花之间的连接
    gotoxy(70, 13);
    printf("\\|");     //注意\为转义字符。想要输入\,必须在前面需要转义
    gotoxy(70, 14);
    printf("`|/");
    gotoxy(70, 15);
    printf("\\|");
    gotoxy(71, 16);
    printf("| /");
    gotoxy(71, 17);
    printf("|");
    gotoxy(67, 17);
    color(10);
    printf("\\\\\\\\");        //草地
    gotoxy(73, 17);
    printf("//");
    gotoxy(67, 18);
    color(2);
    printf("^^^^^^^^");

}
/**
 * 菜单选项边框
 */

void welcom()
{
    title();            //欢迎界面上的标题
    flower();
    int n;
    int i, j = 1;
    color(14);                                          //黄色边框
    for (i = 9; i <= 20; i++)                           //循环y纵坐标,打印输出上下边框===
    {
        for (j = 15; j <= 60; j++)                      //循环x横坐标,打印输出左右边框||
        {
            gotoxy(j, i);
            if (i == 9 || i == 20) printf("=");            //输出上下边框===
            else if (j == 15 || j == 59) printf("||");    //输出左右边框||
        }
    }
    /**
     * 菜单选项的文字
     */
    color(13);                        //设置字体为红色
    gotoxy(22, 12);                   //设置显示位置
    printf("1.开始游戏");             //输出文字“1.开始游戏”
    gotoxy(44, 12);
    printf("2.按键说明");
    gotoxy(22, 17);
    printf("3.游戏规则");
    gotoxy(44, 17);
    printf("4.退出");
    do {
        gotoxy(30, 22);
        color(3);
        printf("请选择[1 2 3 4]:[ ]\b\b");
        color(14);
        scanf("%d", &n);                //输入选项
    } while (n > 4 || n < 1);   //判断输入是否正确

    switch (n)
    {
    case 1:                     //输入“1”
        system("cls");             //清屏
        DrwaGameframe();          \
            Gameplay();
        break;
    case 2:                     //输入“2”
        explation();
        break;
    case 3:                     //输入“3”
        regulation();
        break;
    case 4:                     //输入“4”
        close();
        break;
    }
}
/**
 * 制作游戏窗口
 */

void DrwaGameframe()
{
    gotoxy(FrameX + Frame_width - 7, FrameY - 2);       //设置游戏名称的显示位置
    color(11);                                     //将字体颜色设置为亮蓝色
    printf("趣味俄罗斯方块");                      //打印游戏名称
    gotoxy(FrameX + 2 * Frame_width + 3, FrameY + 7);    //设置上边框的显示位置
    color(2);                                      //将字体颜色设置为深绿色
    printf("**********");                            //打印下一个出现方块的上边框
    gotoxy(FrameX + 2 * Frame_width + 13, FrameY + 7);
    color(3);                                      //将字体颜色设置为深蓝绿色
    printf("下一出现方块:");
    gotoxy(FrameX + 2 * Frame_width + 3, FrameY + 13);
    color(2);
    printf("**********");                            //打印下一个出现方块的下边框
    gotoxy(FrameX + 2 * Frame_width + 3, FrameY + 17);
    color(14);                                    //将字体颜色设置为黄色
    printf("↑键:旋转");
    gotoxy(FrameX + 2 * Frame_width + 3, FrameY + 19);
    printf("空格:暂停游戏");
    gotoxy(FrameX + 2 * Frame_width + 3, FrameY + 15);
    printf("Esc:退出游戏");
    gotoxy(FrameX, FrameY);
    color(12);                                     //将字体颜色设置为红色
    printf("X");                                    //打印框角
    gotoxy(FrameX + 2 * Frame_width - 2, FrameY);
    printf("[");
    gotoxy(FrameX, FrameY + Frame_height);
    printf("^");
    gotoxy(FrameX + 2 * Frame_width - 2, FrameY + Frame_height);
    printf("a");
    for (i = 2; i < 2 * Frame_width - 2; i += 2)
    {
        gotoxy(FrameX + i, FrameY);
        printf("=");                                 //打印上横框
    }
    for (i = 2; i < 2 * Frame_width - 2; i += 2)
    {
        gotoxy(FrameX + i, FrameY + Frame_height);
        printf("=");                                 //打印下横框
        a[FrameX + i][FrameY + Frame_height] = 2;    //标记下横框为游戏边框,防止方块出界
    }
    for (i = 1; i < Frame_height+1; i++)
    {
        gotoxy(FrameX, FrameY + i);
        printf("|");                                 //打印左竖框
        a[FrameX][FrameY + i] = 2;                   //标记左竖框为游戏边框,防止方块出界
    }
    for (i = 1; i < Frame_height; i++)
    {
        gotoxy(FrameX + 2 * Frame_width - 2, FrameY + i);
        printf("|");                                       //打印右竖框
        a[FrameX + 2 * Frame_width - 2][FrameY + i] = 2;   //标记右竖框为游戏边框,防止方块出界   
    }
}

/**
 * 制作俄罗斯方块
 */
void MakeTetris(xin* tetris)
{
    a[tetris->x][tetris->y] = b[0];        //中心方块位置的图形状态
    switch (tetris->flag)                      //共7大类,19种类型
    {
    case 1:         /*田字方块 ■■
                                ■■  */
    {
        color(10);
        a[tetris->x][tetris->y - 1] = b[1];
        a[tetris->x + 2][tetris->y - 1] = b[2];
        a[tetris->x + 2][tetris->y] = b[3];
        break;
    }
    case 2:         /*直线方块 ■■■■*/
    {
        color(13);
        a[tetris->x - 2][tetris->y] = b[1];
        a[tetris->x + 2][tetris->y] = b[2];
        a[tetris->x + 4][tetris->y] = b[3];
        break;
    }
    case 3:         /*直线方块  ■
                               ■
                               ■
                               ■  */
    {
        color(13);
        a[tetris->x][tetris->y - 1] = b[1];
        a[tetris->x][tetris->y - 2] = b[2];
        a[tetris->x][tetris->y + 1] = b[3];
        break;
    }
    case 4:         /*T字方块 ■■■
                                 ■  */
    {
        color(11);
        a[tetris->x - 2][tetris->y] = b[1];
        a[tetris->x + 2][tetris->y] = b[2];
        a[tetris->x][tetris->y + 1] = b[3];
        break;
    }
    case 5:         /* 顺时针90°T字方块   ■
                                         ■■
                                         ■*/
    {
        color(11);
        a[tetris->x][tetris->y - 1] = b[1];
        a[tetris->x][tetris->y + 1] = b[2];
        a[tetris->x - 2][tetris->y] = b[3];
        break;
    }
    case 6:         /* 顺时针180°T字方块   ■
                                           ■■■*/
    {
        color(11);
        a[tetris->x][tetris->y - 1] = b[1];
        a[tetris->x - 2][tetris->y] = b[2];
        a[tetris->x + 2][tetris->y] = b[3];
        break;
    }
    case 7:           /*顺时针270°T字方块 ■
                                           ■■
                                         ■  */
    {
        color(11);
        a[tetris->x][tetris->y - 1] = b[1];
        a[tetris->x][tetris->y + 1] = b[2];
        a[tetris->x + 2][tetris->y] = b[3];
        break;
    }
    case 8:         /* Z字方块  ■■
                                   ■■*/
    {
        color(14);
        a[tetris->x][tetris->y + 1] = b[1];
        a[tetris->x - 2][tetris->y] = b[2];
        a[tetris->x + 2][tetris->y + 1] = b[3];
        break;
    }
    case 9:         /* 顺时针Z字方块  ■
                                     ■■
                                   ■  */
    {
        color(14);
        a[tetris->x][tetris->y - 1] = b[1];
        a[tetris->x - 2][tetris->y] = b[2];
        a[tetris->x - 2][tetris->y + 1] = b[3];
        break;
    }
    case 10:          /* 反Z字方块    ■■
                                     ■■   */
    {
        color(14);
        a[tetris->x][tetris->y - 1] = b[1];
        a[tetris->x - 2][tetris->y - 1] = b[2];
        a[tetris->x + 2][tetris->y] = b[3];
        break;
    }
    case 11:      /* 顺时针反Z字方块  ■
                                       ■■
                                       ■  */
    {
        color(14);
        a[tetris->x][tetris->y + 1] = b[1];
        a[tetris->x - 2][tetris->y - 1] = b[2];
        a[tetris->x - 2][tetris->y] = b[3];
        break;
    }
    case 12:        /* 7字方块    ■■
                                     ■
                                   ■ */
    {
        color(12);
        a[tetris->x][tetris->y - 1] = b[1];
        a[tetris->x][tetris->y + 1] = b[2];
        a[tetris->x - 2][tetris->y - 1] = b[3];
        break;
    }
    case 13:        /* 顺时针90°7字方块     ■
                                          ■■■  */
    {
        color(12);
        a[tetris->x - 2][tetris->y] = b[1];
        a[tetris->x + 2][tetris->y - 1] = b[2];
        a[tetris->x + 2][tetris->y] = b[3];
        break;
    }
    case 14:        /* 顺时针180°7字方块  ■
                                            ■
                                          ■■  */
    {
        color(12);
        a[tetris->x][tetris->y - 1] = b[1];
        a[tetris->x][tetris->y + 1] = b[2];
        a[tetris->x + 2][tetris->y + 1] = b[3];
        break;
    }
    case 15:        /* 顺时针270°7字方块   ■■■
                                             ■     */
    {
        color(12);
        a[tetris->x - 2][tetris->y] = b[1];
        a[tetris->x - 2][tetris->y + 1] = b[2];
        a[tetris->x + 2][tetris->y] = b[3];
        break;
    }
    case 16:          /* 反7字方块   ■■
                                      ■
                                       ■    */
    {
        color(9);
        a[tetris->x][tetris->y + 1] = b[1];
        a[tetris->x][tetris->y - 1] = b[2];
        a[tetris->x + 2][tetris->y - 1] = b[3];
        break;
    }
    case 17:      /* 顺时针90°反7字方块   ■■■
                                               ■*/
    {
        color(9);
        a[tetris->x - 2][tetris->y] = b[1];
        a[tetris->x + 2][tetris->y + 1] = b[2];
        a[tetris->x + 2][tetris->y] = b[3];
        break;
    }
    case 18:        /* 顺时针180°反7字方块  ■
                                              ■
                                          ■■    */
    {
        color(9);
        a[tetris->x][tetris->y - 1] = b[1];
        a[tetris->x][tetris->y + 1] = b[2];
        a[tetris->x - 2][tetris->y + 1] = b[3];
        break;
    }
    case 19:        /* 顺时针270°反7字方块  ■
                                             ■■■*/
    {
        color(9);
        a[tetris->x - 2][tetris->y] = b[1];
        a[tetris->x - 2][tetris->y - 1] = b[2];
        a[tetris->x + 2][tetris->y] = b[3];
        break;
    }
    }
}
/**
 * 打印俄罗斯方块
 */
void PrintTetris(xin* tetris)
{
    for (i = 0; i < 4; i++)                    //数组b[4]中有4个元素,循环这4个元素,让每个元素的值都为1
    {
        b[i] = 1;                         //数组b[4]的每个元素的值都为1
    }
    MakeTetris(tetris);                  //制作游戏窗口
    for (i = tetris->x - 2; i <= tetris->x + 4; i += 2)
    {
        for (j = tetris->y - 2; j <= tetris->y + 1; j++)    //循环方块所有可能出现的位置
        {
            if (a[i][j] == 1 && j > FrameY)         //如果这个位置上有方块
            {
                gotoxy(i, j);
                printf("■");                         //打印边框内的方块
            }
        }
    }
    //打印菜单信息
    gotoxy(FrameX + 2 * Frame_width + 3, FrameY + 1);     //设置打印位置
    color(4);
    printf("level : ");
    color(12);
    printf(" %d", tetris->level);                     //输出等级
    gotoxy(FrameX + 2 * Frame_width + 3, FrameY + 3);
    color(4);
    printf("score : ");
    color(12);
    printf(" %d", tetris->score);                     //输出分数
    gotoxy(FrameX + 2 * Frame_width + 3, FrameY + 5);
    color(4);
    printf("speed : ");
    color(12);
    printf(" %dms", tetris->speed);             //输出速度
}

/**
 * 判断是否可移动
 */
int ifMove(xin* tetris)
{
    if (a[tetris->x][tetris->y] != 0)//当中心方块位置上有图案时,返回值为0,即不可移动
    {
        return 0;
    }
    else
    {
        if (
            (tetris->flag == 1 && (a[tetris->x][tetris->y - 1] == 0 &&//当为田字方块且除中心方块位置外,其他"■"字方块位置上无图案时,说明这个位置能够放下田字方块,可以移动到这个位置,返回值为1,即可移动
                a[tetris->x + 2][tetris->y - 1] == 0 && a[tetris->x + 2][tetris->y] == 0)) ||
            //或为直线方块且除中心方块位置外,其他"■"字方块位置上无图案时,返回值为1,即可移动
            (tetris->flag == 2 && (a[tetris->x - 2][tetris->y] == 0 &&
                a[tetris->x + 2][tetris->y] == 0 && a[tetris->x + 4][tetris->y] == 0)) ||
            (tetris->flag == 3 && (a[tetris->x][tetris->y - 1] == 0 &&    //直线方块(竖)
                a[tetris->x][tetris->y - 2] == 0 && a[tetris->x][tetris->y + 1] == 0)) ||
            (tetris->flag == 4 && (a[tetris->x - 2][tetris->y] == 0 &&    //T字方块
                a[tetris->x + 2][tetris->y] == 0 && a[tetris->x][tetris->y + 1] == 0)) ||
            (tetris->flag == 5 && (a[tetris->x][tetris->y - 1] == 0 &&    //T字方块(顺时针90°)
                a[tetris->x][tetris->y + 1] == 0 && a[tetris->x - 2][tetris->y] == 0)) ||
            (tetris->flag == 6 && (a[tetris->x][tetris->y - 1] == 0 &&    //T字方块(顺时针180°)
                a[tetris->x - 2][tetris->y] == 0 && a[tetris->x + 2][tetris->y] == 0)) ||
            (tetris->flag == 7 && (a[tetris->x][tetris->y - 1] == 0 &&    //T字方块(顺时针270°)
                a[tetris->x][tetris->y + 1] == 0 && a[tetris->x + 2][tetris->y] == 0)) ||
            (tetris->flag == 8 && (a[tetris->x][tetris->y + 1] == 0 &&    //Z字方块
                a[tetris->x - 2][tetris->y] == 0 && a[tetris->x + 2][tetris->y + 1] == 0)) ||
            (tetris->flag == 9 && (a[tetris->x][tetris->y - 1] == 0 &&    //Z字方块(顺时针180°)
                a[tetris->x - 2][tetris->y] == 0 && a[tetris->x - 2][tetris->y + 1] == 0)) ||
            (tetris->flag == 10 && (a[tetris->x][tetris->y - 1] == 0 &&    //Z字方块(反转)
                a[tetris->x - 2][tetris->y - 1] == 0 && a[tetris->x + 2][tetris->y] == 0)) ||
            (tetris->flag == 11 && (a[tetris->x][tetris->y + 1] == 0 &&//Z字方块(反转+顺时针180°)
                a[tetris->x - 2][tetris->y - 1] == 0 && a[tetris->x - 2][tetris->y] == 0)) ||
            (tetris->flag == 12 && (a[tetris->x][tetris->y - 1] == 0 &&    //7字方块
                a[tetris->x][tetris->y + 1] == 0 && a[tetris->x - 2][tetris->y - 1] == 0)) ||
            (tetris->flag == 15 && (a[tetris->x - 2][tetris->y] == 0 &&    //7字方块(顺时针90°)
                a[tetris->x - 2][tetris->y + 1] == 0 && a[tetris->x + 2][tetris->y] == 0)) ||
            (tetris->flag == 14 && (a[tetris->x][tetris->y - 1] == 0 &&    //7字方块(顺时针180°)
                a[tetris->x][tetris->y + 1] == 0 && a[tetris->x + 2][tetris->y + 1] == 0)) ||
            (tetris->flag == 13 && (a[tetris->x - 2][tetris->y] == 0 &&    //7字方块(顺时针270°)
                a[tetris->x + 2][tetris->y - 1] == 0 && a[tetris->x + 2][tetris->y] == 0)) ||
            (tetris->flag == 16 && (a[tetris->x][tetris->y + 1] == 0 &&    //7字方块(反转)
                a[tetris->x][tetris->y - 1] == 0 && a[tetris->x + 2][tetris->y - 1] == 0)) ||
            (tetris->flag == 19 && (a[tetris->x - 2][tetris->y] == 0 &&//7字方块(反转+顺时针90°)
                a[tetris->x - 2][tetris->y - 1] == 0 && a[tetris->x + 2][tetris->y] == 0)) ||
            (tetris->flag == 18 && (a[tetris->x][tetris->y - 1] == 0 &&//7字方块(反转+顺时针180°)
                a[tetris->x][tetris->y + 1] == 0 && a[tetris->x - 2][tetris->y + 1] == 0)) ||
            (tetris->flag == 17 && (a[tetris->x - 2][tetris->y] == 0 &&//7字方块(反转+顺时针270°)
                a[tetris->x + 2][tetris->y + 1] == 0 && a[tetris->x + 2][tetris->y] == 0)))
        {
            return 1;
        }
    }
    return 0;
}

/**
 * 清除俄罗斯方块的痕迹
 */
void CleanTetris(xin* tetris)
{
    for (i = 0; i < 4; i++)            //数组b[4]中有4个元素,循环这4个元素,让每个元素的值都为0
    {
        b[i] = 0;                 //数组b[4]的每个元素的值都为0
    }
    MakeTetris(tetris);             //制作俄罗斯方块
    for (i = tetris->x - 2; i <= tetris->x + 4; i += 2)     //■X■■  X为中心方块
    {
        for (j = tetris->y - 2; j <= tetris->y + 1; j++)        /* ■
                                                               ■
                                                               X
                                                                 ■    */
        {
            if (a[i][j] == 0 && j > FrameY)     //如果这个位置上没有图案,并且处于游戏界面当中
            {
                gotoxy(i, j);
                printf("  ");                        //清除方块
            }
        }
    }
}
/**
 * 判断是否满行并删除满行的俄罗斯方块
 */
void Del_Fullline(xin* tetris)    //当某行有Frame_width-2个方块时,则满行消除
{
    int k, del_rows = 0;                          //分别用于记录某行方块的个数和删除方块的行数的变量
    for (j = FrameY + Frame_height - 1; j >= FrameY + 1; j--)
    {
        k = 0;
        for (i = FrameX + 2; i < FrameX + 2 * Frame_width - 2; i += 2)
        {
            if (a[i][j] == 1)                     //纵坐标依次从下往上,横坐标依次由左至右判断是否满行
            {
                k++;                              //记录此行方块的个数
                if (k == Frame_width - 2)          //如果满行
                {
                    for (k = FrameX + 2; k < FrameX + 2 * Frame_width - 2; k += 2)    //删除满行的方块
                    {
                        a[k][j] = 0;
                        gotoxy(k, j);
                        printf("  ");
                    }
                    //如果删除行以上的位置有方块,则先清除,再将方块下移一个位置
                    for (k = j - 1; k > FrameY; k--)
                    {
                        for (i = FrameX + 2; i < FrameX + 2 * Frame_width - 2; i += 2)
                        {
                            if (a[i][k] == 1)
                            {
                                a[i][k] = 0;
                                gotoxy(i, k);
                                printf("  ");
                                a[i][k + 1] = 1;
                                gotoxy(i, k + 1);
                                printf("■");
                            }
                        }
                    }
                    j++;                   //方块下移后,重新判断删除行是否满行
                    del_rows++;    //记录删除方块的行数
                }
            }
        }
    }
    tetris->score += 100 * del_rows;         //每删除一行,得100分
    if (del_rows > 0 && (tetris->score % 1000 == 0 || tetris->score / 1000 > tetris->level - 1))
    {                                //如果得1000分即累计删除10行,速度加快20ms并升一级
        tetris->speed -= 20;
        tetris->level++;
    }
}

/**
 * 随机产生俄罗斯方块类型的序号
 */
void Flag(xin* tetris)
{
    tetris->number++;                         //记住产生方块的个数
    srand(time(NULL));                      //初始化随机数
    if (tetris->number == 1)
    {
        tetris->flag = rand() % 19 + 1;      //记住第一个方块的序号
    }
    tetris->next = rand() % 19 + 1;           //记住下一个方块的序号
}
/**
 * 开始游戏
 */
void Gameplay()
{
    int n;
    xin t, * tetris = &t;                                //定义结构体的指针并指向结构体变量
    char ch;                                             //定义接收键盘输入的变量
    tetris->number = 0;                                  //初始化俄罗斯方块数为0个
    tetris->speed = 200;                                 //初始移动速度为300ms
    tetris->score = 0;                                   //初始游戏的分数为0分
    tetris->level = 1;                                   //初始游戏为第1关
    while (1)                                            //循环产生方块,直至游戏结束
    {
        Flag(tetris);                                     //得到产生俄罗斯方块类型的序号
        Temp = tetris->flag;                              //记住当前俄罗斯方块序号
        tetris->x = FrameX + 2 * Frame_width + 6;            //获得预览界面方块的x坐标
        tetris->y = FrameY + 10;                             //获得预览界面方块的y坐标
        tetris->flag = tetris->next;                         //获得下一个俄罗斯方块的序号
        PrintTetris(tetris);                                 //调用打印俄罗斯方块方法
        tetris->x = FrameX + Frame_width;                    //获得游戏窗口中心方块x坐标
        tetris->y = FrameY - 1;                              //获得游戏窗口中心方块y坐标
        tetris->flag = Temp;
        //按键操作
        while (1)                                      //控制方块方向,直至方块不再下移
        {
        label:PrintTetris(tetris);            //打印俄罗斯方块
            Sleep(tetris->speed);             //延缓时间
            CleanTetris(tetris);                     //清除痕迹
            Temp1 = tetris->x;                       //记住中心方块横坐标的值
            Temp2 = tetris->flag;                    //记住当前俄罗斯方块序号
            if (_kbhit())                            //判断是否有键盘输入,有则用ch↓接收
            {
                ch = _getch();
                if (ch == 75)                             //按“←”键则向左动,中心横坐标减2
                {
                    tetris->x -= 2;
                }
                if (ch == 77)                             //按“→”键则向右动,中心横坐标加2
                {
                    tetris->x += 2;
                }
                if (ch == 80)                             //按“↓”键则加速下落
                {
                    if (ifMove(tetris) != 0)
                    {
                        tetris->y += 2;
                    }
                    if (ifMove(tetris) == 0)
                    {
                        tetris->y = FrameY + Frame_height - 2;
                    }
                }
                if (ch == 72)                             //按“↑”键则变体,即当前方块顺时针转90度
                {
                    if (tetris->flag >= 2 && tetris->flag <= 3) //如果是直线方块
                    {
                        tetris->flag++;
                        tetris->flag %= 2;
                        tetris->flag += 2;
                    }
                    if (tetris->flag >= 4 && tetris->flag <= 7) //如果是T字方块
                    {
                        tetris->flag++;
                        tetris->flag %= 4;
                        tetris->flag += 4;
                    }
                    if (tetris->flag >= 8 && tetris->flag <= 11) //如果是Z字方块
                    {
                        tetris->flag++;
                        tetris->flag %= 4;
                        tetris->flag += 8;
                    }
                    if (tetris->flag >= 12 && tetris->flag <= 15) //如果是7字方块
                    {
                        tetris->flag++;
                        tetris->flag %= 4;
                        tetris->flag += 12;
                    }
                    if (tetris->flag >= 16 && tetris->flag <= 19) //如果是反7字方块
                    {
                        tetris->flag++;
                        tetris->flag %= 4;
                        tetris->flag += 16;
                    }
                }
                if (ch == 32)                                          //按空格键,暂停
                {
                    PrintTetris(tetris);
                    while (1)
                    {
                        if (_kbhit())                                //再按空格键,继续游戏
                        {
                            ch = _getch();
                            if (ch == 32)
                            {
                                goto label;
                            }
                        }
                    }
                }
                if (ch == 27)
                {
                    system("cls");
                    memset(a, 0, 6400 * sizeof(int));           //初始化BOX数组
                    welcom();
                }
                if (ifMove(tetris) == 0)                     //如果不可动,上面操作无效
                {
                    tetris->x = Temp1;
                    tetris->flag = Temp2;
                }
                else                                          //如果可动,执行操作
                {
                    goto label;
                }
            }
            tetris->y++;                                     //如果没有操作指令,方块向下移动
            if (ifMove(tetris) == 0)                          //如果向下移动且不可动,方块放在此处
            {
                tetris->y--;
                PrintTetris(tetris);
                Del_Fullline(tetris);
                break;
            }
        }
        for (i = tetris->y - 2; i < tetris->y + 2; i++)
        {
            if (i == FrameY)
            {
                system("cls");         //清屏
                gotoxy(29, 7);          //设置显示位置
                printf("   \n");
                color(12);              //红色
                printf("\t\t\t■■■■    ■       ■    ■■     \n");
                printf("\t\t\t■            ■■    ■    ■  ■   \n");
                printf("\t\t\t■■■    ■  ■  ■    ■   ■  \n");
                printf("\t\t\t■            ■   ■ ■    ■  ■   \n");
                printf("\t\t\t■■■■    ■      ■    ■■     \n");
                gotoxy(17, 18);
                color(14);
                printf("我要重新玩一局-------1");
                gotoxy(44, 18);
                printf("不玩了,退出吧-------2\n");
                int n;
                do {
                    gotoxy(32, 20);
                    printf("选择【1/2】:");
                    color(11);
                    scanf("%d", &n);        //输入1或2
                } while (n > 2 || n < 1);
                switch (n)               //分支语句
                {
                case 1:
                    system("cls");
                    Replay(tetris);           //重新开始游戏
                    break;
                case 2:
                    exit(0);
                    break;
                }
            }
        }
        tetris->flag = tetris->next;              //清除下一个俄罗斯方块的图形(右边窗口)
        tetris->x = FrameX + 2 * Frame_width + 6;
        tetris->y = FrameY + 10;
        CleanTetris(tetris);
    }
}

/**
 * 重新开始游戏
 */
void Replay(xin* tetris)
{
    system("cls");                  //清屏
    memset(a, 0, 6400 * sizeof(int)); //初始化BOX数组,否则不会正常显示方块,导致游戏直接结束
    DrwaGameframe();                   //制作游戏窗口
    Gameplay();                         //开始游戏
}

/**
 * 按键说明
 */
void explation()
{
    int i, j = 1;
    system("cls");                        //清屏
    color(13);                            //粉色
    gotoxy(32, 4);                        //设置显示位置
    printf("按 键 说 明");
    color(2);
    for (i = 5; i <= 17; i++)               //输出上下边框===
    {
        for (j = 15; j <= 60; j++)      //输出左右边框||
        {
            gotoxy(j, i);
            if (i == 5 || i == 17) printf("=");
            else if (j == 15 || j == 59) printf("||");
        }
    }
    color(3);
    gotoxy(18, 7);
    printf("tip1: 玩家可以通过 ← →方向键来移动方块");
    color(10);
    gotoxy(18, 9);
    printf("tip2: 通过 ↑使方块旋转");
    color(14);
    gotoxy(18, 11);
    printf("tip3: 通过 ↓加速方块下落");
    color(11);
    gotoxy(18, 13);
    printf("tip4: 按空格键暂停游戏,再按空格键继续");
    color(4);
    gotoxy(18, 15);
    printf("tip5: 按ESC退出游戏");
    _getch();                                //按任意键返回欢迎界面
    system("cls");                         //清屏 
    main();                                 //返回主函数
}

/**
 * 游戏规则
 */
void regulation()
{
    int i, j = 1;
    system("cls");
    color(13);
    gotoxy(34, 4);
    printf("游 戏 规 则");
    color(2);
    for (i = 5; i <= 19; i++)               //输出上下边框===
    {
        for (j = 12; j <= 70; j++)      //输出左右边框||
        {
            gotoxy(j, i);
            if (i == 5 || i == 19) printf("=");
            else if (j == 12 || j == 69) printf("||");
        }
    }
    color(12);
    gotoxy(16, 7);
    printf("tip1: 不同形状的小方块从屏幕上方落下,玩家通过调整");
    gotoxy(22, 9);
    printf("方块的位置和方向,使他们在屏幕底部拼出完整的");
    gotoxy(22, 11);
    printf("一条或几条");
    color(14);
    gotoxy(16, 13);
    printf("tip2: 每消除一行,积分涨100");
    color(11);
    gotoxy(16, 15);
    printf("tip3: 每累计1000分,会提升一个等级");
    color(10);
    gotoxy(16, 17);
    printf("tip4: 提升等级会使方块下落速度加快,游戏难度加大");
    _getch();                //按任意键返回欢迎界面
    system("cls");
    welcom();
}

/**
*  退出
*/
void close()
{
    exit(0);
}

运行结果如图:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如果您发现本篇中有什么错误的地方,您可以在评论区给我留言,我会及时更正的,谢谢!
本人qq:846581636
期待你的关注
感谢大家的支持,谢谢!

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值