2021-05-15

俄罗斯方块(bug未修复前)

include<stdio.h>

include<graphics.h>

include<time.h>

include<conio.h>//kbhit的使用

int score = 0;//分数
int rank = 0;//等级

define BLOCK_COUNT 5

define BLOCK_WIDTH 5

define BLOCK_HEIGHT 5

define UNIT_SIZE 20

define START_X 130

define START_Y 30

define KEY_UP 72

define KEY_RIGHT 77

define KEY_DOWN 80

define KEY_LEFT 75

define KEY_SPACE 32

int speed = 500;
int minX = 30;
int minY = 30;

typedef enum {
BLOCK_UP,
BLOCK_RIGHT,
BLOCK_DOWN,
BLOCK_LEFT
}block_dir_t;

typedef enum {
MOVE_DOWN,
MOVE_LEFT,
MOVE_RIGHT,
}move_dir_t;

int NextIndex = -1;//下一个方块的种类
int BlockIndex = -1;//当前方块的种类

int color[BLOCK_COUNT] = {
GREEN,CYAN,MAGENTA,BROWN,YELLOW
};

//访问数组
int visit[30][15];
int markColor[30][15];//表示对应位置的颜色

int block[BLOCK_COUNT * 4][BLOCK_WIDTH][BLOCK_HEIGHT] = {
// 1型方块
{
0,0,0,0,0,
0,0,1,0,0,
0,0,1,0,0,
0,0,1,0,0,
0,0,0,0,0,
},
{
0,0,0,0,0,
0,0,0,0,0,
0,1,1,1,0,
0,0,0,0,0,
0,0,0,0,0,
},
{
0,0,0,0,0,
0,0,1,0,0,
0,0,1,0,0,
0,0,1,0,0,
0,0,0,0,0,
},
{
0,0,0,0,0,
0,0,0,0,0,
0,1,1,1,0,
0,0,0,0,0,
0,0,0,0,0,
},
//L性方块
{
0,0,0,0,0,
0,0,1,0,0,
0,0,1,0,0,
0,0,1,1,0,
0,0,0,0,0,
},
{
0,0,0,0,0,
0,0,0,0,0,
0,1,1,1,0,
0,1,0,0,0,
0,0,0,0,0,
},
{
0, 0, 0, 0, 0,
0, 1, 1, 0, 0,
0, 0, 1, 0, 0,
0, 0, 1, 0, 0,
0, 0, 0, 0, 0,
},
{
0,0,0,0,0,
0,0,0,1,0,
0,1,1,1,0,
0,0,0,0,0,
0,0,0,0,0,
},
//田形方块
{
0,0,0,0,0,
0,1,1,0,0,
0,1,1,0,0,
0,0,0,0,0,
0,0,0,0,0,
},
{
0,0,0,0,0,
0,1,1,0,0,
0,1,1,0,0,
0,0,0,0,0,
0,0,0,0,0,
},
{
0,0,0,0,0,
0,1,1,0,0,
0,1,1,0,0,
0,0,0,0,0,
0,0,0,0,0,
},
{
0,0,0,0,0,
0,1,1,0,0,
0,1,1,0,0,
0,0,0,0,0,
0,0,0,0,0,
},
//T形方块
{
0,0,0,0,0,
0,1,1,1,0,
0,0,1,0,0,
0,0,0,0,0,
0,0,0,0,0,
},
{
0,0,0,0,0,
0,0,0,1,0,
0,0,1,1,0,
0,0,0,1,0,
0,0,0,0,0,
},
{
0,0,0,0,0,
0,0,1,0,0,
0,1,1,1,0,
0,0,0,0,0,
0,0,0,0,0,
},
{
0,0,0,0,0,
0,1,0,0,0,
0,1,1,0,0,
0,1,0,0,0,
0,0,0,0,0,
},
//Z形方块
{
0,0,0,0,0,
0,1,1,0,0,
0,0,1,1,0,
0,0,0,0,0,
0,0,0,0,0,
},
{
0,0,0,0,0,
0,0,1,0,0,
0,1,1,0,0,
0,1,0,0,0,
0,0,0,0,0,
},
{
0,0,0,0,0,
0,1,1,0,0,
0,0,1,1,0,
0,0,0,0,0,
0,0,0,0,0,
},
{
0,0,0,0,0,
0,0,1,0,0,
0,1,1,0,0,
0,1,0,0,0,
0,0,0,0,0,
}
};//=>;标志着数组的结束

//实现欢迎界面
void welcome(void) {
//初始化画布
initgraph(550,660);

//设置窗口标题
HWND window = GetHWnd();//获取窗口
SetWindowText(window, _T("俄罗斯方块  设计师:晓宁 "));//设置窗口标题

//设置文本的字体样式
//setfont(40, 0, _T("微软雅黑"));//setfont这个函数已经弃用,代替它的是新函数settextstyle
settextstyle(40, 0,_T( "微软雅黑"));//只指定高度,不指定宽度
setcolor(WHITE);
outtextxy(205,200,_T("俄罗斯方块"));

//setfont(22, 0, _T("楷体"));//setfont这个函数已经弃用,代替它的是新函数settextstyle
settextstyle(22, 0, _T("楷体"));
outtextxy(175, 300, _T("C++,从俄罗斯方块开始!"));

Sleep(3000);//睡眠 (暂停) 3000毫秒 , 3秒钟

}

//初始化游戏场景
void initGameScene(void) {
char str[16];

//清除屏幕
cleardevice();

rectangle(27, 27, 336, 635);
rectangle(29, 29, 334, 635);
rectangle(370, 50, 515, 195);

//setfont(22, 0, _T("楷体"));//setfont这个函数已经弃用,代替它的是新函数settextstyle
settextstyle(24, 0, _T("楷体"));
setcolor(LIGHTGRAY);
outtextxy(405, 215,_T("下一个"));

setcolor(RED);
outtextxy(405, 280, _T("分数"));
sprintf_s(str, "%d", score);
outtextxy(415, 310, str);

outtextxy(405, 375, _T("等级"));
sprintf_s(str, "%d", rank);
outtextxy(415, 405, str);

//操作说明
setcolor(LIGHTBLUE);
outtextxy(390, 475, _T("操作说明"));
outtextxy(390, 500, _T("↑:旋转"));
outtextxy(390, 525, _T("↓:下降"));
outtextxy(390, 550, _T("←:左移"));
outtextxy(390, 575, _T("→:右移"));
outtextxy(390, 600, _T("空格:暂停"));

}

void clearBlock(void) {//清除方块
setcolor(BLACK);
settextstyle(23,0,_T("楷体"));
for (int i = 1;i < BLOCK_HEIGHT;i++) {
for (int j = 0;j < BLOCK_HEIGHT;j++) {
//"■"
int x = 391 + j * UNIT_SIZE;
int y = 71 + i * UNIT_SIZE;
outtextxy(x,y, "■");
}
}
}

void clearBlock(int x, int y, block_dir_t dir) {

}

//在右上角区域中,绘制下一个方块
//绘制方块:在指定位置绘制指定方块的指定方向
void drawBlock(int x,int y,int blockIndex,block_dir_t dir) {
setcolor(color[NextIndex]);
settextstyle(23, 0, _T("楷体"));
int id = blockIndex * 4 + dir;
for (int i = 1;i < BLOCK_HEIGHT;i++) {
for (int j = 0;j < BLOCK_HEIGHT;j++) {
//"■"
if (block[4 * NextIndex][i][j] == 1) {
int x2 = 391 + j * UNIT_SIZE;
int y2 = 71 + i * UNIT_SIZE;
outtextxy(x2, y2, "■");
}
}
}
}
//清除指定位置指定方向的方块
//参数x:方块的左上角的x坐标
//参数y:方块的左上角在游戏区域内的坐标,距离游戏区域顶部的距离
void clearBlock(int x, int y , block_dir_t dir) {
setcolor(BLACK);
int id = BlockIndex * 4 + dir;
y += START_Y;

for (int i = 0;i < 5;i++) {
    for (int j = 0;j < 5;j++) {
        if (block[id][i][j] == 1) {
            //擦出该方块的第i行的第j列
            outtextxy(x + 20 * j, y + i * 20, "■");
        }
    }
}

}

void nextblock(void) {
clearBlock();//清除右上角区域

//随机选择一种方块
srand(time(NULL));//使用时间函数的返回值,来作为随机种子
NextIndex = rand() % BLOCK_COUNT;

drawBlock(391,71);

}

//如果在指定位置可以向指定方向移动,就返回1,否则就返回0
int moveable(int x0, int y0, move_dir_t moveDir, block_dir_t blockDir) {
//计算当前方块的左(zuo)上角在30*15的游戏区的位置(第多少行,第多少列)
int x = (y0 - minY) / UNIT_SIZE;
int y = (x0 - minX) / UNIT_SIZE;

int id = BlockIndex * 4 + blockDir;
int ret = 0;

if (moveDir = MOVE_DOWN) {
    for (int i = 0;i < 5;i++) {
        for (int j = 0;j < 5;j++) {
            if (block[id][i][j] == 1 &&
                (x + i + 1 >= 30 || visit[x + i + 1][y + j] == 1)) {
                ret = 0;
            }
        }
    }
}
else if (moveDir == MOVE_LEFT) {
    for (int i = 0;i < 5;i++) {
        for (int j = 0;j < 5;j++) {
            if (block[id][i][j] == 1 &&
                (y + j == 0 || visit[x + i][y + j - 1] == 1)) {
                ret = 0;
            }
        }
    }
}
else if (moveDir == MOVE_RIGHT) {
    for (int i = 0;i < 5;i++) {
        for (int j = 0;j < 5;j++) {
            if (block[id][i][j] == 1 &&
                (y + j + 1 >= 15 || visit[x + i][y + j + 1] == 1))) {
                ret = 0;
            }
        }
    }
}
return ret;

}

//检测游戏是否结束
void failCheck() {
if (!moveable(START_X, START_Y, MOVE_DOWN, BLOCK_UP)) {
setcolor(WHITE);
settextstyle(45,0,"隶体");
outtextxy(75,300,"GAME OVER!");
Sleep(1000);
system("pause");
closegraph();
exit(0);
}
}

//判断当前方块是否可以转向到指定方向
//注意,此时还没有转到指定方向!!!
int rotatable(int x, int y, block_dir_t) {
int id = BlockIndex * 4 + dir;
int xIndex = (y - minY) / 20;
int yIndex = (x - minX) / 20;

if (!moveable(x, y, MOVE_DOWN, dir)) {
    return 0;
}

for (int i = 0;i < 5;i++) {
    for (int j = 0;j < 5;j++) {
        if (block[id][i][j]==1&&
            (yIndex +j<0|| yIndex +j>=15||visit[xIndex +1][yIndex +j]==1)) {
            return 0;

        }
    }
}

}

void wait(int interval) {//500
int cout = interval / 10;
for (int i = 0;i < cout;i++) {
Sleep(10);
if (_kbhit()) {
return;
}
}
}

void mark(int x, int y, int blockIndex, block_dir_t dir) {
int id = blockIndex * 4 + dir;
int x2 = (y - minX)/20;
int y2 = (x - minY) / 20;

for (int i = 0;i < 5;i++) {
    for (int j = 0;j < 5;j++) {
        if (block[id][i][j] == 1) {
            visit[x2+i][y2+j] = 1;
            markColor[x2 + i][y2 + j] = color[blockIndex];
        }
    }
}

}

void move(void) {
int x = START_X;
int y = START_Y;
int k = 0;
block_dir_t blockDir = BLOCK_UP;
int curSpeed = speed;

//检测游戏是否结束
failCheck();

//持续向下降落
while (1) {
    if (_kbhit()) {
        int key = _getch();
        if (key == KEY_SPACE) {
            _getch();
        }
    }

    //清除当前方块
    clearBlock(x, k, blockDir);

    if (_kbhit()) {
        int key = _getch();
        if (key == KEY_UP) {

            block_dir_t nextDir = (block_dir_t)((blockDir + 1) % 4);

            if (rotatable(x, y + k, nextDir) {

                blockDir = nextDir;

            }
        }
        else if (key == KEY_DOWN) {
            curSpeed = 50;
        }
        else if (key == KEY_LEFT) {
            if (moveable(x, y + k + 20, MOVE_LEFT, blockDir)) {
                x -= 20;
            }
        }
        else if (key == KEY_RIGHT) {
            if (moveable(x, y + k + 20, MOVE_RIGHT, blockDir)) {
                x += 20;
                //x=x+20;
            }
        }
    }

    k += 20;

    //绘制当前方块
    drawBlock(x, y + k, BlockIndex, blockDir);
    wait(curSpeed);

    

    //方块的"固化"处理
    if (!moveable(x, y + k, MOVE_DOWN, blockDir)) {
        mark(x, y + k, BlockIndex, blockDir);
        break;
    }
}

}

void newblock(void) {
//确定即将使用的方块的类别
BlockIndex = NextIndex;

//绘制刚从顶部下降的方块
drawBlock(START_X, START_Y);

//让新方块停0.1秒
Sleep(100);

//在右上角区域,绘制下一个方块
nextblock();

//方块降落
move();

}

//消除第i行,并把上面的行都下移
void down(int i) {
for (int i = x;i > 0;i--) {
//消除第i行,第j列的方块
for (j = 0;j < 15;j++) {
if (visit[i - 1][j]) {
visit[i][j] = 1;
markColor[i][j] = markColor[i - 1][j];
setcolor(markColor[i][j]);
outtextxy(20 * j + minX, 20 * j + minY, "■");
}
else {
visit[i][j] = 0;
setcolor(BLACK);
outtextxy(20 * j + mianX, 20 * j + mianY, "■");
}
}
}
//清除顶行(就是行标为0的哪一行)
SetBkColor(BLACK);
for (int j = 0;j < 15;j++) {
visit[0][j] = 0;
outtextxy(20 * j + minX, minY, "■");
}

}

//更新分数,参数line表示消除行数
void addScore(int lines) {
char sty[32];

setcolor(RED);
score += lines * 10;
sprintf(str, "%d", score);
outtextxy(415, 310, str);

}

void updateGrade() {
//更新等级的提示
//假设:50分一级
rank = score / 50;
char str[16];
sprintf(str,"%d",rank);
outtextxy(425, 405, str);
//更新速度
//注意:更新速度,速度越快,speed越小!
//最慢:500,最快:100
speed = 500 - rank * 100;
if (speed <= 100) {
speed = 100;
}
}

void check(void) {
int i, j;
int clearLines = 0;
for (int i = 29;i >= 0;i--) {
//检查第i行有没有满
for (int j = 0;j < 15 && visit[i][j];j++);

    //执行到此处,有两种情况:
    //1.第i行没有满,即表示有空位 此时j<15
    //2.第j行已满了,此时j>=15
    if (j >= 15) {
        //此时,第i行已经满了,就需要消除第i行
        down(i);//消除第i行,并把上面的行都下移
        i++;//因为最外层的循环有i--,所以我们先i++,使得下次循环,再把这一行检查一下
        clearLines++;
    }
}
//更新分数
addScore(clearLines);
//更新等级
//等级越高,方块下降速度越快,难度越大
//(更新等级提示,更新速度)
updateGrade();

}

int main(void) {
welcome();
initGameScene();

//产生新方块
nextblock();
Sleep(500);
    
//初始化访问数组
memset(visit, 0, sizeof(visit));

while (1) {
    newblock();

    //消除满行,并更新分数和速度
    check();

}

system("pause");

closegraph();

return 0;

}

©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容