刚刚进入软件开发行业的时候加了不少QQ技术群,其实群里面好多都是扯淡的,而且里面的人水平不一,多么简单的问题都问得出来,还有想拜师啊之类的,后来就都退了。但是其中一个群里面有一个公告是让大家写一个字符界面的俄罗斯方块,感觉很好玩儿,就试着写了一个,玩儿自己写的“游戏”感觉还是挺爽的,虽然很简陋,但是刚刚开始嘛,还是很有成就感的。
开始想了很多办法,不知道怎么来定义数据结构,还有里面的好多变换,新手是痛苦的,平时看起来那么简单的东西做起来原来那么难。但是最后还是笨人有笨法,当时的我多么佩服自己这个想法。整个的界面很简单也很简陋,不过还是有些可玩儿性的。基本就是模仿原来玩儿过的图形界面的俄罗斯方块做的,分成10个速度级别啊,一次消几行得分加倍啊,分数越高速度越快啊等等,也就这些了。最后还找了一个比较方形的字符来表示方块,一个笑脸哦,咔咔,效果还是不错嘀
整个工程很简单,一共就两个文件,这个是头文件Tetris2.h
#define WIDTH 12
#define HEIGHT 18
#define LEVEL 9
DWORD level[10] = {1000, 900, 800, 700, 600, 500, 400, 300, 200, 100};
int data[HEIGHT][WIDTH];
int nextData[4][4];
int TotalScore = 0;
int baseLevel = 0;
int addLevel = 0;
BOOL bGameOver;
struct Location
{
int h;
int l;
Location(){}
Location(int hang, int lie)
{
h = hang;
l = lie;
}
};
Location block[7][4][4] = {
{//I
{Location(1,0), Location(0,0), Location(2,0),Location(3,0)},
{Location(0,1), Location(0,0), Location(0,2),Location(0,3)},
{Location(1,0), Location(0,0), Location(2,0),Location(3,0)},
{Location(0,1), Location(0,0), Location(0,2),Location(0,3)}
},
{//O
{Location(0,0), Location(0,1), Location(1,0),Location(1,1)},
{Location(0,0), Location(0,1), Location(1,0),Location(1,1)},
{Location(0,0), Location(0,1), Location(1,0),Location(1,1)},
{Location(0,0), Location(0,1), Location(1,0),Location(1,1)}
},
{//T
{Location(0,1), Location(0,0), Location(0,2),Location(1,1)},
{Location(1,1), Location(1,0), Location(0,1),Location(2,1)},
{Location(1,1), Location(1,0), Location(0,1),Location(1,2)},
{Location(1,0), Location(0,0), Location(1,1),Location(2,0)}
},
{//J
{Location(1,1), Location(0,1), Location(2,0),Location(2,1)},
{Location(1,1), Location(1,0), Location(0,0),Location(1,2)},
{Location(1,0), Location(0,1), Location(0,0),Location(2,0)},
{Location(0,1), Location(0,0), Location(0,2),Location(1,2)}
},
{//L
{Location(1,0), Location(0,0), Location(2,0),Location(2,1)},
{Location(0,1), Location(0,0), Location(0,2),Location(1,0)},
{Location(1,1), Location(0,1), Location(0,0),Location(2,1)},
{Location(1,1), Location(1,0), Location(0,2),Location(1,2)}
},
{//S
{Location(0,1), Location(0,2), Location(1,0),Location(1,1)},
{Location(1,0), Location(0,0), Location(1,1),Location(2,1)},
{Location(0,1), Location(0,2), Location(1,0),Location(1,1)},
{Location(1,0), Location(0,0), Location(1,1),Location(2,1)}
},
{//Z
{Location(0,1), Location(0,0), Location(1,1),Location(1,2)},
{Location(1,1), Location(1,0), Location(0,1),Location(2,0)},
{Location(0,1), Location(0,0), Location(1,1),Location(1,2)},
{Location(1,1), Location(1,0), Location(0,1),Location(2,0)}
}
};
Location newBlock[4];
Location nextBlock[4];
void Init();
void PrintData();
int GameStart();
void UpdateData(Location newLoc);
BOOL MoveDown();
BOOL MoveLeft();
BOOL MoveRight();
BOOL ChangeA(int shape, int &state);
BOOL ChangeB(int shape, int &state);
int GetScore();
void RemoveData(int* full, int count);
下面这个是源文件Tetris2.cpp
#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <conio.h>
#include "Tetris2.h"
int main()
{
while(1)
{
Init();
PrintData();
int result;
result = GameStart();
switch (result)
{
case 0:
{
system("cls");
printf("Do you want to quit the game?(y/n)");
while(1)
{
char ch=_getch();
if (ch == 'y')
return 0;
if (ch == 'n')
{
break;
}
}
continue;
}
case -1:
{
system("cls");
printf("Game Over!\nYour Score:%d\nDo you want to try again?(y/n)", TotalScore);
while(1)
{
char ch=_getch();
if (ch == 'n')
return 0;
if (ch == 'y')
{
break;
}
}
continue;
}
}
}
return 0;
}
void Init()
{
for (int i=0; i<HEIGHT; i++)
{
for (int j=0; j<WIDTH; j++)
{
data[i][j] = 0;
}
}
TotalScore = 0;
addLevel = 0;
bGameOver = FALSE;
system("cls");
printf("Please input your start Level(0~9):");
while(1)
{
char ch = _getche();
if (ch>='0' && ch<='9')
{
baseLevel = ch-48;
break;
}
else
{
system("cls");
printf("Wrong Input!\nPlease input your start Level(0~9):");
}
}
system("cls");
}
void PrintData()
{
COORD coord1 = {0, 0};
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord1);
char cNextData[4][5];
for (int i=0; i<4; i++)
{
for (int j=0; j<4; j++)
{
if (nextData[i][j])
{
cNextData[i][j] = 2;
}
else
cNextData[i][j] = ' ';
}
cNextData[i][4] = '\0';
}
cNextData[3][4] = '\0';
char cData[HEIGHT][WIDTH+3];
for (int i=0; i<HEIGHT; i++)
{
cData[i][0] = '.';
for (int j=0; j<WIDTH; j++)
{
if (data[i][j] == 1)
cData[i][j+1] = 2;
else
cData[i][j+1] = ' ';
}
cData[i][WIDTH+1] = '.';
cData[i][WIDTH+2] = '\n';
}
cData[HEIGHT-1][WIDTH+2] = '\0';
for (int j=0; j<WIDTH+15; j++)
printf(".");
printf("\n%s\n", cData);
for (int j=0; j<WIDTH+2; j++)
printf("~");
for (int i=0; i<4; i++)
{
COORD coord2 = {WIDTH+2, i+1};
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord2);
printf(". %s .", cNextData[i]);
}
COORD coord3 = {WIDTH+2, 5};
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord3);
printf(".............");
COORD coord4 = {WIDTH+2, 7};
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord4);
printf(" SCORE:%d", TotalScore);
COORD coord5 = {WIDTH+2, 9};
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord5);
printf(" LEVEL:%d", baseLevel+addLevel>9?9:baseLevel+addLevel);
COORD coord6 = {WIDTH+2, 11};
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord6);
printf(" 操作说明");
COORD coord7 = {WIDTH+2, 12};
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord7);
printf(" LEFT :A");
COORD coord8 = {WIDTH+2, 13};
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord8);
printf(" RIGHT :D");
COORD coord9 = {WIDTH+2, 14};
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord9);
printf(" DOWN :S");
COORD coord10 = {WIDTH+2, 15};
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord10);
printf(" BOTTOM:W");
COORD coord11 = {WIDTH+2, 16};
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord11);
printf(" CHANGE:J&K");
COORD coord12 = {WIDTH+2, 17};
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord12);
printf(" QUIT :Q");
COORD coord13 = {WIDTH+2, 18};
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord13);
printf(" PAUSE :P");
}
int GameStart()
{
//随机产生图形和图形的形态(乘以2防止开始两个方块相同)
srand((unsigned)time(NULL)*2);
int nextShape = rand()%7;
srand((unsigned)time(NULL)*2);
int nextState = rand()%4;
//获得方块初始数据
for (int i=0; i<4; i++)
{
nextBlock[i] = block[nextShape][nextState][i];
}
while(1)
{
//在出现下一个方块之前判断游戏有没有结束
if (bGameOver)
{
Sleep(1000);
return -1;
}
//根据现在的分数设定方块下落速度
addLevel = TotalScore/100;
//记录当前的形状和状态
int shape = nextShape;
int state = nextState;
//随机产生下一个图形和图形的形态
srand((unsigned)GetTickCount());
nextShape = rand()%7;
srand((unsigned)GetTickCount());
nextState = rand()%4;
//获得当前的方块并获得下一个方块初始数据
for (int i=0; i<4; i++)
{
newBlock[i] = nextBlock[i];
nextBlock[i] = block[nextShape][nextState][i];
}
//图形中心点的初始坐标
Location loc(1, WIDTH/2);
//定位并更新数据
UpdateData(loc);
PrintData();
DWORD starttime = 0;
DWORD endtime = GetTickCount();
while(1)
{
if (_kbhit())
{
BOOL b = FALSE;
BOOL down = TRUE;
char ch = _getch();
switch(ch)
{
case 's':
down = b = MoveDown();
break;
case 'w':
while(down = MoveDown());
break;
case 'a':
b = MoveLeft();
break;
case 'd':
b = MoveRight();
break;
case 'j':
b = ChangeA(shape, state);
break;
case 'k':
b = ChangeB(shape, state);
break;
case 'q':
return 0;
case 'p':
system("pause");
system("cls");
break;
}
if (!down)
{
int score = GetScore();
if (score)
TotalScore = TotalScore + 2*score - 1;
PrintData();
break;
}
if (b)
{
endtime = GetTickCount();
if (endtime-starttime>=level[baseLevel+addLevel>9?9:baseLevel+addLevel])
{
starttime = endtime;
if (MoveDown())
PrintData();
else
{
int score = GetScore();
if (score)
TotalScore = TotalScore + 2*score - 1;
PrintData();
break;
}
}
PrintData();
}
}//if (_kbhit())
endtime = GetTickCount();
if (endtime-starttime>=level[baseLevel+addLevel>9?9:baseLevel+addLevel])
{
starttime = endtime;
if (MoveDown())
PrintData();
else
{
int score = GetScore();
if (score)
TotalScore = TotalScore + 2*score - 1;
PrintData();
break;
}
}
}//while(1)
}//while(1)
}
void UpdateData(Location newLoc)
{
int hoffset = newLoc.h - newBlock[0].h;
int loffset = newLoc.l - newBlock[0].l;
int nexth = 1 - nextBlock[0].h;
int nextl = 1 - nextBlock[0].l;
for (int i=0; i<4; i++)
for (int j=0; j<4; j++)
{
nextData[i][j] = 0;
}
for (int i=0; i<4; i++)
{
newBlock[i].h += hoffset;
newBlock[i].l += loffset;
data[newBlock[i].h][newBlock[i].l] = 1;
nextData[nextBlock[i].h + nexth][nextBlock[i].l + nextl] = 1;
}
}
BOOL MoveDown()
{
Location temp[4];
for (int i=0; i<4; i++)
{
temp[i].h = newBlock[i].h+1;
temp[i].l = newBlock[i].l;
if (temp[i].h >= HEIGHT)
return FALSE;
}
for (int i=0; i<4; i++)
{
data[newBlock[i].h][newBlock[i].l] = 0;
}
for (int i=0; i<4; i++)
{
if (data[temp[i].h][temp[i].l])
{
for (int i=0; i<4; i++)
{
data[newBlock[i].h][newBlock[i].l] = 1;
}
if (newBlock[0].h == 1 && newBlock[0].l == WIDTH/2)
bGameOver = TRUE;
return FALSE;
}
}
Location newLoc = temp[0];
UpdateData(newLoc);
return TRUE;
}
BOOL MoveLeft()
{
Location temp[4];
for (int i=0; i<4; i++)
{
temp[i].h = newBlock[i].h;
temp[i].l = newBlock[i].l-1;
if (temp[i].l < 0)
return FALSE;
}
for (int i=0; i<4; i++)
{
data[newBlock[i].h][newBlock[i].l] = 0;
}
for (int i=0; i<4; i++)
{
if (data[temp[i].h][temp[i].l])
{
for (int i=0; i<4; i++)
{
data[newBlock[i].h][newBlock[i].l] = 1;
}
return FALSE;
}
}
Location newLoc = temp[0];
UpdateData(newLoc);
return TRUE;
}
BOOL MoveRight()
{
Location temp[4];
for (int i=0; i<4; i++)
{
temp[i].h = newBlock[i].h;
temp[i].l = newBlock[i].l+1;
if (temp[i].l >= WIDTH)
return FALSE;
}
for (int i=0; i<4; i++)
{
data[newBlock[i].h][newBlock[i].l] = 0;
}
for (int i=0; i<4; i++)
{
if (data[temp[i].h][temp[i].l])
{
for (int i=0; i<4; i++)
{
data[newBlock[i].h][newBlock[i].l] = 1;
}
return FALSE;
}
}
Location newLoc = temp[0];
UpdateData(newLoc);
return TRUE;
}
BOOL ChangeA(int shape, int &state)
{
Location temp[4];
for (int i=0; i<4; i++)
{
temp[i] = block[shape][(state+1)%4][i];
}
int hoffset = newBlock[0].h - temp[0].h;
int loffset = newBlock[0].l - temp[0].l;
for (int i=0; i<4; i++)
{
temp[i].h += hoffset;
temp[i].l += loffset;
if (temp[i].h >=HEIGHT || temp[i].l<0 || temp[i].l>=WIDTH)
return FALSE;
}
for (int i=0; i<4; i++)
{
data[newBlock[i].h][newBlock[i].l] = 0;
}
for (int i=0; i<4; i++)
{
if (data[temp[i].h][temp[i].l])
{
for (int i=0; i<4; i++)
{
data[newBlock[i].h][newBlock[i].l] = 1;
}
return FALSE;
}
}
for (int i=0; i<4; i++)
{
newBlock[i] = temp[i];
data[newBlock[i].h][newBlock[i].l] = 1;
}
state++;
state %= 4;
return TRUE;
}
BOOL ChangeB(int shape, int &state)
{
Location temp[4];
for (int i=0; i<4; i++)
{
temp[i] = block[shape][(state+3)%4][i];
}
int hoffset = newBlock[0].h - temp[0].h;
int loffset = newBlock[0].l - temp[0].l;
for (int i=0; i<4; i++)
{
temp[i].h += hoffset;
temp[i].l += loffset;
if (temp[i].h >=HEIGHT || temp[i].l<0 || temp[i].l>=WIDTH)
return FALSE;
}
for (int i=0; i<4; i++)
{
data[newBlock[i].h][newBlock[i].l] = 0;
}
for (int i=0; i<4; i++)
{
if (data[temp[i].h][temp[i].l])
{
for (int i=0; i<4; i++)
{
data[newBlock[i].h][newBlock[i].l] = 1;
}
return FALSE;
}
}
for (int i=0; i<4; i++)
{
newBlock[i] = temp[i];
data[newBlock[i].h][newBlock[i].l] = 1;
}
state += 3;
state %= 4;
return TRUE;
}
int GetScore()
{
int score = 0;
int full[4];
for (int i=0; i<4; i++)
{
int h = newBlock[i].h;
BOOL same = FALSE;
for (int j=0; j<score; j++)
{
if (h == full[j])
same = TRUE;
}
if (same)
{
continue;
}
int test = 1;
for (int j=0; j<WIDTH; j++)
{
test *= data[h][j];
}
if (test)
{
full[score] = h;
score++;
}
}
for (int k=0; k<5; k++)
{
for (int i=0; i<score; i++)
{
for (int j=0; j<WIDTH; j++)
{
data[full[i]][j] = k%2;
}
}
if (score)
{
PrintData();
Sleep(100);
}
}
Sleep(100);
RemoveData(full, score);
//PrintData();
return score;
}
void RemoveData(int *full, int count)
{
//先从大到小排序
for (int i=0; i<count-1; i++)
{
for (int j=i+1; j<count; j++)
{
if (full[i]<full[j])
{
int temp = full[i];
full[i] = full[j];
full[j] = temp;
}
}
}
for (int i=0; i<count; i++)
{
if (i == count-1)
{
for (int j=full[i]+i; j>0; j--)
{
for (int k=0; k<WIDTH; k++)
{
data[j][k] = data[j-i-1][k];
}
}
}
else
{
for (int j=full[i]-i; j>full[i+1]-i+1; j--)
{
for (int k=0; k<WIDTH; k++)
{
data[j][k] = data[j-i-1][k];
}
}
}
}
}