#include<stdio.h>
#include<graphics.h>
#include<stdlib.h>
#include<time.h>
#include<conio.h>//kbhit()的使用
int score = 0;
int rank = 0;
int speed = 500;//500毫秒
int minX = 30;
int minY = 30;
#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
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_HEIGHT][BLOCK_WIDTH] = {
//条形方块
{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,
}
};//3种方块有4种形态,一个方块占据的空间在5*5的格子里面
//欢迎界面
void welcome(void)
{
initgraph(550, 660);
//设置窗口标题
HWND window= GetHWnd();//获取窗口
SetWindowText(window, _T("俄罗斯方块 2023年版本"));//设置窗口标题
//设置文本的样式
setfont(40, 0, _T("微软雅黑"));
setcolor(WHITE);
outtextxy(205, 200, _T("俄罗斯方块"));
setfont(22, 0, _T("楷体"));
outtextxy(175, 300, _T("2023年版本 编程小游戏"));
Sleep(3000);//睡眠 3秒
}
//初始化游戏场景
void initGameScene()
{
char str[16];
//清除屏幕
cleardevice();
rectangle(27, 27, 336, 635);
rectangle(29, 29, 334, 633);
rectangle(379, 50, 515, 195);
//设置文本的样式
setfont(24, 0, _T("楷体"));
setcolor(LIGHTGRAY);//灰色
outtextxy(405, 215, _T("下一个"));
setcolor(RED);
outtextxy(405, 280, _T("分数:"));
sprintf(str,"%d", score);//按指定格式把score打印到str;
outtextxy(415, 310, str);
outtextxy(405, 370, _T("等级:"));
sprintf(str, "%d", rank);
outtextxy(425, 405,str);
setcolor(LIGHTBLUE);
outtextxy(390, 475, _T("操作说明"));
outtextxy(390, 500, "↑:旋转");
outtextxy(390, 525, "↓:下降");
outtextxy(390, 550, "←:左移");
outtextxy(390, 575, "→:右移");
outtextxy(390, 600, "空格:暂停");
}
//清除方块
void clearBlock(int x,int y)
{
setcolor(BLACK);
setfont(23, 0, "楷体");
for (int i = 0; i < BLOCK_HEIGHT; i++)
{
for (int j = 0; j < BLOCK_WIDTH; j++)
{
int w = x + UNIT_SIZE * j;
int z = y + UNIT_SIZE * i;
outtextxy(w , z , "■");
}
}
}
//清楚指定位置指定方块的函数
//参数x:方块的左上角坐标
//参数y:方块的左上角在游戏区域内的坐标,距离游戏顶部的距离
void clearBlock(int x, int y,block_dir_t dir)
{
setcolor(BLACK);
setfont(23, 0, "楷体");
int id = BlockIndex * 4 + dir;
y += START_Y;
/*x += START_X;*/
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 5; j++)
{
if (block[id][i][j]==1)
{
//擦除该方块的第i行的第j列
outtextxy(x + j * 20, y + i * 20, "■");
}
}
}
}
//在右上角区域中,绘制下一个方块
void drawBlock(int x,int y)
{
setcolor(color[NextIndex]);
setfont(23, 0, "楷体");
for (int i = 0; i < BLOCK_HEIGHT; i++)
{
for (int j = 0; j < BLOCK_WIDTH; j++)
{
if (block[4*NextIndex][i][j]==1)
{
int w = x + UNIT_SIZE * j;
int z = y + UNIT_SIZE * i;
outtextxy(w,z, "■");
}
}
}
}
//绘制方块:z在指定位置绘制指定方块
void drawBlock(int x, int y, int blockIndex, block_dir_t dir)
{
setcolor(color[blockIndex]);
setfont(23, 0, "楷体");
int id = blockIndex * 4 + dir;
for (int i = 0; i < BLOCK_HEIGHT; i++)
{
for (int j = 0; j < BLOCK_WIDTH; j++)
{
if (block[id][i][j] == 1)
{
int w = x + UNIT_SIZE * j;
int z = y + UNIT_SIZE * i;
outtextxy(w, z, "■");
}
}
}
}
//产生新方块
void nextblock(void)
{
clearBlock(391,71);//清除右上角缓冲区
//随机选择一种方块
srand(time(NULL));//使用时间函数的返回值,来作为随机种子
NextIndex=rand() % BLOCK_COUNT;//生成随机数,取余可以得到5种 0到4随机的值
drawBlock(391,71);//在右上角区域中,绘制下一个方块
}
//如果在指定位置可以向指定方向移动,就返回1 ,否则就返回0
int moveable(int x0, int y0, move_dir_t moveDir,block_dir_t blockDir)
{
//计算当前方块在左上角30*15的游戏区中的位置,第多少行,多少列
int x = (y0 - minY)/UNIT_SIZE;//表示多少行
int y = (x0 - minX) / UNIT_SIZE;//表示多少列
int id = BlockIndex * 4 + blockDir;
int ret = 1;
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 failCheak(void)
{
if (!moveable(START_X, START_Y, MOVE_DOWN, BLOCK_UP))
{
setcolor(WHITE);
setfont(45, 0, "隶体");
outtextxy(75, 300, "GAME OVER!");
Sleep(1000);
system("pause");
closegraph();
exit(0);//结束
}
}
//判断当前方块是否可以转到指定方向
//注意,此时还没有转到指定方向
int rotatable(int x, int y, block_dir_t dir)
{
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 &&
(j + yIndex < 0 || yIndex + j>15 || visit[xIndex + i][yIndex + i] == 1))
{
return 0;
}
}
}
return 1;
}
//等待的时间间隔
void wait(int interval)
{
int count = interval / 10;
for (int i = 0; i < count; 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 - minY)/20;
int y2= (x - minX) / 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;
int curSpeed = speed;
block_dir_t blockDir=BLOCK_UP;
//检测游戏是否结束
failCheak();
//持续向下降落
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;
}
}
}
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);
//让新出现的方块暂停一会,让用户识别
Sleep(100);//停留0.1秒
//在右上角绘制下一个方块
nextblock();
//方块降落过程
move();
}
//消除第x行
void down(int x)
{
for (int i = x; i>0; i--)
{
//消除第i行第j列的方块消除
for (int 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(j * 20 + minX, i * 20 + minY, "■");
}
else
{
visit[i][j] = 0;
setcolor(BLACK);
outtextxy(j * 20 + minX, i * 20 + minY, "■");
}
}
}
//清楚最顶上的哪一行,就是清楚定0行
setcolor(BLACK);
for (int j = 0; j < 15; j++)
{
visit[0][j] = 0;
outtextxy(j * 20 + minX, minY, "■");
}
}
void addScore(int lines)
{
char str[32];
setcolor(RED);
score += 10* lines;
sprintf(str, "%d", score);//按指定格式把score打印到str;
outtextxy(415, 310, str);
}
void updateGrade()
{
char str[16];
//跟新等级,50分一级
rank = score / 50 + 1;
sprintf(str, "%d", rank);//按指定格式把score打印到str;
outtextxy(425, 405, str);
//速度跟新,等级高,速度快
speed = 500 - rank * 10;
if (speed <= 100)
{
speed = 100;
}
}
void cheak()
{
int i = 0;
int j = 0;
int clearLines = 0;
int rank = 0;
for ( i = 29; i >=0; i--)
{
for ( j =0; j <15&&visit[i][j]; j++)//visit[i][j]==1等于visit[i][j]
{
//执行到此处时有两种情况,
//第I行没有满,j<15
//第i行满了。j>=15
if (j >= 14)
{
//此时第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));//把整个数组设置为0,清空数组
while (1)
{
newblock();
//消除满行,更新分数
cheak();
}
system("pause");
closegraph();
return 0;
}
C++俄罗斯方块
最新推荐文章于 2024-06-11 22:53:55 发布