俄羅斯方塊(bug未修復(fù)前)
include<stdio.h>
include<graphics.h>
include<time.h>
include<conio.h>//kbhit的使用
int score = 0;//分?jǐn)?shù)
int rank = 0;//等級(jí)
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;//下一個(gè)方塊的種類
int BlockIndex = -1;//當(dāng)前方塊的種類
int color[BLOCK_COUNT] = {
GREEN,CYAN,MAGENTA,BROWN,YELLOW
};
//訪問數(shù)組
int visit[30][15];
int markColor[30][15];//表示對(duì)應(yīng)位置的顏色
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,
}
};//=>;標(biāo)志著數(shù)組的結(jié)束
//實(shí)現(xiàn)歡迎界面
void welcome(void) {
//初始化畫布
initgraph(550,660);
//設(shè)置窗口標(biāo)題
HWND window = GetHWnd();//獲取窗口
SetWindowText(window, _T("俄羅斯方塊 設(shè)計(jì)師:曉寧 "));//設(shè)置窗口標(biāo)題
//設(shè)置文本的字體樣式
//setfont(40, 0, _T("微軟雅黑"));//setfont這個(gè)函數(shù)已經(jīng)棄用,代替它的是新函數(shù)settextstyle
settextstyle(40, 0,_T( "微軟雅黑"));//只指定高度,不指定寬度
setcolor(WHITE);
outtextxy(205,200,_T("俄羅斯方塊"));
//setfont(22, 0, _T("楷體"));//setfont這個(gè)函數(shù)已經(jīng)棄用,代替它的是新函數(shù)settextstyle
settextstyle(22, 0, _T("楷體"));
outtextxy(175, 300, _T("C++,從俄羅斯方塊開始!"));
Sleep(3000);//睡眠 (暫停) 3000毫秒 , 3秒鐘
}
//初始化游戲場(chǎng)景
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這個(gè)函數(shù)已經(jīng)棄用,代替它的是新函數(shù)settextstyle
settextstyle(24, 0, _T("楷體"));
setcolor(LIGHTGRAY);
outtextxy(405, 215,_T("下一個(gè)"));
setcolor(RED);
outtextxy(405, 280, _T("分?jǐn)?shù)"));
sprintf_s(str, "%d", score);
outtextxy(415, 310, str);
outtextxy(405, 375, _T("等級(jí)"));
sprintf_s(str, "%d", rank);
outtextxy(415, 405, str);
//操作說明
setcolor(LIGHTBLUE);
outtextxy(390, 475, _T("操作說明"));
outtextxy(390, 500, _T("↑:旋轉(zhuǎn)"));
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) {
}
//在右上角區(qū)域中,繪制下一個(gè)方塊
//繪制方塊:在指定位置繪制指定方塊的指定方向
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, "■");
}
}
}
}
//清除指定位置指定方向的方塊
//參數(shù)x:方塊的左上角的x坐標(biāo)
//參數(shù)y:方塊的左上角在游戲區(qū)域內(nèi)的坐標(biāo),距離游戲區(qū)域頂部的距離
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();//清除右上角區(qū)域
//隨機(jī)選擇一種方塊
srand(time(NULL));//使用時(shí)間函數(shù)的返回值,來作為隨機(jī)種子
NextIndex = rand() % BLOCK_COUNT;
drawBlock(391,71);
}
//如果在指定位置可以向指定方向移動(dòng),就返回1,否則就返回0
int moveable(int x0, int y0, move_dir_t moveDir, block_dir_t blockDir) {
//計(jì)算當(dāng)前方塊的左(zuo)上角在30*15的游戲區(qū)的位置(第多少行,第多少列)
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;
}
//檢測(cè)游戲是否結(jié)束
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);
}
}
//判斷當(dāng)前方塊是否可以轉(zhuǎn)向到指定方向
//注意,此時(shí)還沒有轉(zhuǎn)到指定方向!!!
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;
//檢測(cè)游戲是否結(jié)束
failCheck();
//持續(xù)向下降落
while (1) {
if (_kbhit()) {
int key = _getch();
if (key == KEY_SPACE) {
_getch();
}
}
//清除當(dāng)前方塊
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;
//繪制當(dāng)前方塊
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);
//在右上角區(qū)域,繪制下一個(gè)方塊
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, "■");
}
}
}
//清除頂行(就是行標(biāo)為0的哪一行)
SetBkColor(BLACK);
for (int j = 0;j < 15;j++) {
visit[0][j] = 0;
outtextxy(20 * j + minX, minY, "■");
}
}
//更新分?jǐn)?shù),參數(shù)line表示消除行數(shù)
void addScore(int lines) {
char sty[32];
setcolor(RED);
score += lines * 10;
sprintf(str, "%d", score);
outtextxy(415, 310, str);
}
void updateGrade() {
//更新等級(jí)的提示
//假設(shè):50分一級(jí)
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++);
//執(zhí)行到此處,有兩種情況:
//1.第i行沒有滿,即表示有空位 此時(shí)j<15
//2.第j行已滿了,此時(shí)j>=15
if (j >= 15) {
//此時(shí),第i行已經(jīng)滿了,就需要消除第i行
down(i);//消除第i行,并把上面的行都下移
i++;//因?yàn)樽钔鈱拥难h(huán)有i--,所以我們先i++,使得下次循環(huán),再把這一行檢查一下
clearLines++;
}
}
//更新分?jǐn)?shù)
addScore(clearLines);
//更新等級(jí)
//等級(jí)越高,方塊下降速度越快,難度越大
//(更新等級(jí)提示,更新速度)
updateGrade();
}
int main(void) {
welcome();
initGameScene();
//產(chǎn)生新方塊
nextblock();
Sleep(500);
//初始化訪問數(shù)組
memset(visit, 0, sizeof(visit));
while (1) {
newblock();
//消除滿行,并更新分?jǐn)?shù)和速度
check();
}
system("pause");
closegraph();
return 0;
}