运行效果
代码
//游戏相关的数据
/*
1.地图数据-哪些位置有方块、哪些位置是空的
2.浮动的大方块
*/
#include <stdio.h>
#include <stdlib.h>
#include <graphics.h>
#include <time.h>
#include <mmsystem.h>
#include <iostream>
using namespace std;
#pragma comment(lib,"Winmm.lib")
#define BLOCK_COUNT 7
#define DIRECTION_COUNT 4
#define BLOCK_WIDTH 4
#define BLOCK_HEIGHT 4
#define GRID_WIDTH 12 //网格宽带
#define GRID_HIGHT 24 //网格高度 实际高度20 留有4行作为临时区域
#define SLIDER_PX 30//边长30 单位像素
#define WAIT_DELAY 400//等待延时,100毫秒,浮动矩阵向下移动一行
#define SINGLE_DELAY 80//单次延时
#define INFO_WINDOW_WIDTH 200//信息窗体宽度
enum BlockType //方块类型
{
Block_None = -1, //没有方块
Block_0 = 0, //正方形
Block_1 = 1, //直线型
Block_2 = 2, //反L形
Block_3 = 3, //山字形
Block_4 = 4, //反Z形
Block_5 = 5, //正Z形
Block_6 = 6, //正L形
};
const bool bBlockData[BLOCK_COUNT][DIRECTION_COUNT][BLOCK_WIDTH][BLOCK_HEIGHT] =
{
//第一个形状
{
//第一个角度
{
{ false,false,false,false},
{false,true,true,false},
{ false,true,true,false},
{ false,false,false,false}
},
//第二个角度
{
{ false,false,false,false},
{false,true,true,false},
{ false,true,true,false},
{ false,false,false,false}
},
//第三个角度
{
{ false,false,false,false},
{false,true,true,false},
{ false,true,true,false},
{ false,false,false,false}
},
//第四个角度
{
{ false,false,false,false},
{false,true,true,false},
{ false,true,true,false},
{ false,false,false,false}
}
},
//第二个形状
{
//第一个角度
{
{ false,false,true,false},
{false,false,true,false},
{ false,false,true,false},
{ false,false,true,false}
},
//第二个角度
{
{ false,false,false,false},
{false,false,false,false},
{ true,true,true,true},
{ false,false,false,false}
},
//第三个角度
{
{ false,true,false,false},
{false,true,false,false},
{ false,true,false,false},
{ false,true,false,false}
},
//第四个角度
{
{ false,false,false,false},
{true,true,true,true},
{ false,false,false,false},
{ false,false,false,false}
}
},
//第三个形状
{
//第一个角度
{
{ false,false,false,false},
{false,true,false,false},
{ false,true,true,true},
{ false,false,false,false}
},
//第二个角度
{
{ false,false,false,false},
{false,true,true,false},
{ false,true,false,false},
{ false,true,false,false}
},
//第三个角度
{
{ false,false,false,false},
{true,true,true,false},
{ false,false,true,false},
{ false,false,false,false}
},
//第四个角度
{
{ false,false,true,false},
{false,false,true,false},
{ false,true,true,false},
{ false,false,false,false}
}
},
//第四个形状
{
//第一个角度
{
{ false,false,false,false},
{false,true,false,false},
{ true,true,true,false},
{ false,false,false,false}
},
//第二个角度
{
{ false,true,false,false},
{false,true,true,false},
{ false,true,false,false},
{ false,false,false,false}
},
//第三个角度
{
{ false,false,false,false},
{false,true,true,true},
{ false,false,true,false},
{ false,false,false,false}
},
//第四个角度
{
{ false,false,false,false},
{false,false,true,false},
{ false,true,true,false},
{ false,false,true,false}
}
},
//第五个形状
{
//第一个角度
{
{ false,false,false,false},
{false,true,true,false},
{ true,true,false,false},
{ false,false,false,false}
},
//第二个角度
{
{ false,true,false,false},
{false,true,true,false},
{ false,false,true,false},
{ false,false,false,false}
},
//第三个角度
{
{ false,false,false,false},
{false,false,true,true},
{ false,true,true,false},
{ false,false,false,false}
},
//第四个角度
{
{ false,false,false,false},
{false,true,false,false},
{ false,true,true,false},
{ false,false,true,false}
}
},
//第六个形状
{
//第一个角度
{
{ false,false,false,false},
{false,true,true,false},
{ false,false,true,true},
{ false,false,false,false}
},
//第二个角度
{
{ false,false,false,false},
{false,false,true,false},
{ false,true,true,false},
{ false,true,false,false}
},
//第三个角度
{
{ false,false,false,false},
{true,true,false,false},
{ false,true,true,false},
{ false,false,false,false}
},
//第四个角度
{
{ false,false,true,false},
{false,true,true,false},
{ false,true,false,false},
{ false,false,false,false}
}
},
//第七个形状
{
//第一个角度
{
{ false,false,false,false},
{false,false,true,false},
{ true,true,true,false},
{ false,false,false,false}
},
//第二个角度
{
{ false,true,false,false},
{false,true,false,false},
{ false,true,true,false},
{ false,false,false,false}
},
//第三个角度
{
{ false,false,false,false},
{false,true,true,true},
{ false,true,false,false},
{ false,false,false,false}
},
//第四个角度
{
{ false,false,false,false},
{false,true,true,false},
{ false,false,true,false},
{ false,false,true,false}
}
}
};
const int iBlockMinRow[BLOCK_COUNT][DIRECTION_COUNT] = {
{
1,1,1,1
},
{
0,2,3,1
},
{
1,1,1,0
},
{
1,0,1,1
},
{
1,0,1,1
},
{
1,1,1,0
},
{
1,0,1,1
}
};
const int iBlockMinCol[BLOCK_COUNT][DIRECTION_COUNT] = {
{
1,1,1,1
},
{
2,0,1,0
},
{
1,1,0,1
},
{
0,1,1,1
},
{
0,1,1,1
},
{
1,1,0,1
},
{
0,1,1,1
}
};
const int iBlockMaxRow[BLOCK_COUNT][DIRECTION_COUNT] = {
{
2,2,2,2
},
{
3,2,3,1
},
{
2,3,2,2
},
{
2,2,2,3
},
{
2,2,2,3
},
{
2,3,2,2
},
{
2,2,2,3
}
};
const int iBlockMaxCol[BLOCK_COUNT][DIRECTION_COUNT] = {
{
2,2,2,2
},
{
2,3,1,3
},
{
3,2,2,2
},
{
2,2,3,2
},
{
2,2,3,2
},
{
3,2,2,2
},
{
2,2,3,2
}
};
int iGrid[GRID_HIGHT][GRID_WIDTH];
int iFloatBlock[BLOCK_HEIGHT][BLOCK_WIDTH];
int iNextBlock = 0;//下一个方块
int iNextBlockDirection = 0;//下一个方块的方向
int iWaitTime = 0;//每次等待时间,浮动矩阵下降一行
int iFloatBlockRow = 0;//浮动方块开始的行
int iFloatBlockCol = 0;//浮动方块开始的列
int iCurrentBlock = 0;//当前方块的形状
int iCurrentBlockDirection = 0;//当前方块的方向
int iScore = 0; //游戏的分数
int iLastScore = 0;//上次得分
int iMaxScore = 0;//最高得分
/*
接口说明:初始化棋盘
参数说明:无
返回值说明:无
*/
int InitGrid()
{
for (int iRow = 0; iRow < GRID_HIGHT; iRow++)
{
for (int iCol = 0; iCol < GRID_WIDTH; iCol++)
{
iGrid[iRow][iCol] = BlockType::Block_None;
}
}
return 0;
}
/*
接口说明:清空完整行
参数说明:无
返回值说明:无
*/
int ClearLine()
{
int iClearLineCount = 0;//消除的总共行数
int iStartRow = iFloatBlockRow + iBlockMaxRow[iCurrentBlock][iCurrentBlockDirection];
int iEndRow = iFloatBlockRow + iBlockMinRow[iCurrentBlock][iCurrentBlockDirection];
for (int iRow = iStartRow; iRow >= iEndRow; iRow--)
{
bool bClear = true;
for (int iCol = 0; iCol < GRID_WIDTH; iCol++)
{
if (iGrid[iRow][iCol] == BlockType::Block_None)
{
bClear = false;
break;
}
}
if (bClear)//是否需要消行
{
for (int iTempRow = iRow; iTempRow >=4; iTempRow--)
{
for (int iTempCol = 0; iTempCol < GRID_WIDTH; iTempCol++)
{
iGrid[iTempRow][iTempCol] = iGrid[iTempRow - 1][iTempCol];
}
}
iRow++;
//iEndRow++;
iClearLineCount++;
}
}
//奖励机制
switch (iClearLineCount)
{
case 1:
{
iScore += 10;//无额外加分,基础十分
break;
}
case 2:
{
iScore += 25;//额外加5分
break;
}
case 3:
{
iScore += 45;//额外加15分
break;
}
case 4:
{
iScore += 70;//额外加30分
break;
}
defalult:
{
break;//不加分
}
}
return 0;
}
int DrawFloatBlock()
{
//设置线条颜色
setlinecolor(RGB(255, 255, 255));
switch (iCurrentBlock)
{
case BlockType::Block_0:
{
setfillcolor(RGB(255, 0, 0));
break;
}
case BlockType::Block_1:
{
setfillcolor(RGB(89, 176, 189));
break;
}
case BlockType::Block_2:
{
setfillcolor(RGB(20, 101, 165));
break;
}
case BlockType::Block_3:
{
setfillcolor(RGB(235, 213, 0));
break;
}
case BlockType::Block_4:
{
setfillcolor(RGB(137, 64, 134));
break;
}
case BlockType::Block_5:
{
setfillcolor(RGB(218, 132, 0));
break;
}
case BlockType::Block_6:
{
setfillcolor(RGB(54, 154, 49));
break;
}
default:
{
setfillcolor(RGB(0, 0, 0));
break;
}
}
for (int iRow = 0; iRow < BLOCK_HEIGHT; iRow++) {
for (int iCol = 0; iCol < BLOCK_WIDTH; iCol++) {
if(iFloatBlock[iRow][iCol]!=BlockType::Block_None)
fillrectangle((iFloatBlockCol + iCol)* SLIDER_PX, (iFloatBlockRow+iRow - 4)* SLIDER_PX, (iFloatBlockCol +iCol + 1)* SLIDER_PX, (iFloatBlockRow+iRow - 3)* SLIDER_PX);
}
}
return 0;
}
/*
接口说明:初始化浮动的方块
参数说明:无
返回值说明:无
*/
int InitFloatBlock()
{
for (int iRow = 0; iRow < BLOCK_HEIGHT; iRow++) {
for (int iCol = 0; iCol < BLOCK_WIDTH; iCol++) {
iFloatBlock[iRow][iCol] = BlockType::Block_None;
}
}
return 0;
}
/*
接口说明:生成下一个方块
参数说明:无
返回值说明:无
*/
int GenerateNextBlock()
{
iCurrentBlock = iNextBlock;
iCurrentBlockDirection = iNextBlockDirection;
iNextBlock = rand() % 7 ;
iNextBlockDirection = rand() % DIRECTION_COUNT;
return 0;
}
/*
接口说明:加载得分
参数说明:无
返回值说明:无
*/
int LoadScore()
{
FILE* fp = NULL;
fopen_s(&fp, "Score.txt", "r");
if (fp == NULL)
{
return -1;
}
fscanf_s(fp, "%d", &iLastScore);
fscanf_s(fp, "%d", &iMaxScore);
fclose(fp);
return 0;
}
/*
接口说明:保存得分
参数说明:无
返回值说明:无
*/
int SaveScore()
{
FILE* fp = NULL;
fopen_s(&fp, "Score.txt", "w");
if (fp == NULL)
{
return -1;
}
if (iScore > iMaxScore)
{
iMaxScore = iScore;
}
fprintf_s(fp, "%d\n", iScore);
fprintf_s(fp, "%d\n", iMaxScore);
fclose(fp);
return 0;
}
/*
接口说明:绘画游戏信息
参数说明:无
返回值说明:无
*/
int DrwaInfo()
{
int iStartX = GRID_WIDTH * SLIDER_PX;
settextcolor(RGB(255, 255, 255));//设置字体颜色
settextstyle(24, 0, L"楷体");//设置字体样式
WCHAR score[100];
swprintf_s(score, 100, L"分数:%d", iScore);
outtextxy(iStartX+20,20,score);
outtextxy(iStartX + 20, 60, L"下一个方块:");
setlinecolor(RGB(255, 255, 255));//设置线条颜色
rectangle(iStartX + 20, 90, iStartX + 20 + SLIDER_PX * BLOCK_WIDTH,90+SLIDER_PX*BLOCK_HEIGHT);
switch (iNextBlock)
{
case BlockType::Block_0:
{
setfillcolor(RGB(255, 0, 0));
break;
}
case BlockType::Block_1:
{
setfillcolor(RGB(89, 176, 189));
break;
}
case BlockType::Block_2:
{
setfillcolor(RGB(20, 101, 165));
break;
}
case BlockType::Block_3:
{
setfillcolor(RGB(235, 213, 0));
break;
}
case BlockType::Block_4:
{
setfillcolor(RGB(137, 64, 134));
break;
}
case BlockType::Block_5:
{
setfillcolor(RGB(218, 132, 0));
break;
}
case BlockType::Block_6:
{
setfillcolor(RGB(54, 154, 49));
break;
}
default:
{
setfillcolor(RGB(0, 0, 0));
break;
}
}
for (int iRow = 0; iRow < BLOCK_HEIGHT; iRow++)
{
for (int iCol = 0; iCol < BLOCK_HEIGHT; iCol++)
{
if (bBlockData[iNextBlock][iNextBlockDirection][iRow][iCol])
{
fillrectangle(iStartX + 20 + iCol* SLIDER_PX, 90 + iRow * SLIDER_PX, iStartX + 20 + (iCol + 1) * SLIDER_PX, 90 + (iRow + 1) * SLIDER_PX);
}
}
}
swprintf_s(score, 100, L"%d", iLastScore);
swprintf_s(score, 100, L"%d", iMaxScore);
outtextxy(iStartX + 20, 240, L"上次得分:");
outtextxy(iStartX + 20, 270, score);
outtextxy(iStartX + 20, 310, L"最高得分:");
outtextxy(iStartX + 20, 330, score);
return 0;
}
/*
接口说明:初始化浮动方块的开始行列
参数说明:无
返回值说明:无
*/
int InitFloatBlockStarRC()
{
iFloatBlockCol = 4;
iFloatBlockRow=BLOCK_HEIGHT -iBlockMaxRow[iNextBlock][iNextBlockDirection]-1;
return 0;
}
/*
接口说明:获取浮动方块
参数说明:无
返回值说明:无
*/
int GetFloatBlock()
{
for (int iRow = 0; iRow < BLOCK_HEIGHT; iRow++) {
for (int iCol = 0; iCol < BLOCK_WIDTH; iCol++) {
if (bBlockData[iCurrentBlock][iCurrentBlockDirection][iRow][iCol])
{
iFloatBlock[iRow][iCol] = iCurrentBlock;
}
else
{
iFloatBlock[iRow][iCol] = BlockType::Block_None;
}
}
}
return 0;
}
/*
接口说明:尝试移动
参数说明:iBlockType 方块的类型
iBlockDirection 方块的方向
iStarRow 方块矩阵开始的行
iStarCol 方块矩阵开始的列
返回值说明: true 可以移动 false 不能移动
*/
bool TryMove(int iBlockType,int iBlockDirection,int iStartRow,int iStartCol)
{
if (iStartRow + iBlockMaxRow[iBlockType][iBlockDirection] < 0 || iStartRow + iBlockMaxRow[iBlockType][iBlockDirection] >= GRID_HIGHT)
{
return false;
}
if (iStartCol + iBlockMinCol[iBlockType][iBlockDirection] < 0 || iStartCol + iBlockMaxCol[iBlockType][iBlockDirection] >= GRID_WIDTH)
{
return false;
}
for (int iRow = 0; iRow < BLOCK_HEIGHT; iRow++)
{
for (int iCol = 0; iCol < BLOCK_WIDTH; iCol++)
{
if (iStartRow + iRow >= 4 && iStartRow + iRow < GRID_HIGHT && iStartCol + iCol >= 0 && iStartCol + iCol < GRID_WIDTH)
{
//确保测试是否重合的点在网格内
if (iFloatBlock[iRow][iCol] != BlockType::Block_None && iGrid[iStartRow + iRow][iStartCol + iCol] != BlockType::Block_None)
{
return false;
}
}
}
}
return true;
}
/*
接口说明:捕获浮动方块,将浮动方块嵌入到网格中
参数说明:无
返回值说明:无
*/
int CaptureFloatBlock()
{
for (int iRow = 0; iRow < BLOCK_HEIGHT; iRow++)
{
for (int iCol = 0; iCol < BLOCK_WIDTH; iCol++)
{
if (iFloatBlock[iRow][iCol] != BlockType::Block_None)
{
iGrid[iFloatBlockRow + iRow][iFloatBlockCol + iCol] = iFloatBlock[iRow][iCol];
}
}
}
return 0;
}
/*
接口说明:绘画棋盘
参数说明:无
返回值说明:无
*/
int DrawGrid()
{
IMAGE imgBg;
loadimage(&imgBg, L".\\背景.jpg");
putimage(0, 0, &imgBg);
setbkcolor(RGB(237,145,33));
//设置线条颜色
setlinecolor(RGB(255, 255, 255));
for (int iRow = 4; iRow < GRID_HIGHT; iRow++) {
for (int iCol = 0; iCol < GRID_WIDTH; iCol++)
{
switch (iGrid[iRow][iCol])
{
case BlockType::Block_0:
{
setfillcolor(RGB(255, 0, 0));
break;
}
case BlockType::Block_1:
{
setfillcolor(RGB(89, 176, 189));
break;
}
case BlockType::Block_2:
{
setfillcolor(RGB(20, 101, 165));
break;
}
case BlockType::Block_3:
{
setfillcolor(RGB(235, 213, 0));
break;
}
case BlockType::Block_4:
{
setfillcolor(RGB(137, 64, 134));
break;
}
case BlockType::Block_5:
{
setfillcolor(RGB(218, 132, 0));
break;
}
case BlockType::Block_6:
{
setfillcolor(RGB(54, 154, 49));
break;
}
default:
{
setfillcolor(RGB(0, 0, 0));
break;
}
}
fillrectangle(iCol * SLIDER_PX, (iRow - 4) * SLIDER_PX, (iCol + 1) * SLIDER_PX, (iRow - 3) * SLIDER_PX);
}
}
return 0;
}
int main()
{
LoadScore();//游戏开始,加载分数
srand((unsigned int)time(NULL));
InitGrid();
InitFloatBlock();
GenerateNextBlock();//生成第一个方块
GenerateNextBlock();//生成第二个方块
InitFloatBlockStarRC();
GetFloatBlock();
//创建窗口
initgraph(GRID_WIDTH * SLIDER_PX+INFO_WINDOW_WIDTH, (GRID_HIGHT - 4) * SLIDER_PX);
BeginBatchDraw();
mciSendStringW(L"open .\\企鹅峰待机.mp3 alias bgm", NULL, 0, NULL);
mciSendStringW(L"play bgm repeat", NULL, 0, NULL);
while (1)
{
if (GetAsyncKeyState(VK_UP))//获取用户的输入
{
int iTempDirection = (iCurrentBlockDirection+1)%DIRECTION_COUNT;
if (TryMove(iCurrentBlock, iTempDirection, iFloatBlockRow, iFloatBlockCol - 1))
{
iCurrentBlockDirection = iTempDirection;
GetFloatBlock();
}
}
else if(GetAsyncKeyState(VK_LEFT))
{
if (TryMove(iCurrentBlock, iCurrentBlockDirection, iFloatBlockRow , iFloatBlockCol-1))
{
iFloatBlockCol--;
}
}
else if (GetAsyncKeyState(VK_RIGHT))
{
if (TryMove(iCurrentBlock, iCurrentBlockDirection, iFloatBlockRow , iFloatBlockCol+1))
{
iFloatBlockCol++;
}
}
else if (GetAsyncKeyState(VK_DOWN))
{
if (TryMove(iCurrentBlock, iCurrentBlockDirection, iFloatBlockRow + 1, iFloatBlockCol))
{
iFloatBlockRow++;
}
else //不能往下落时就嵌入它
{
if (iFloatBlockRow + iBlockMaxRow[iCurrentBlock][iCurrentBlockDirection] <= 4)
{
//游戏结束
break;
}
CaptureFloatBlock();
ClearLine();
GenerateNextBlock();
InitFloatBlockStarRC();
GetFloatBlock();
}
iWaitTime = 0;
}
if (iWaitTime >= WAIT_DELAY)
{
if (TryMove(iCurrentBlock, iCurrentBlockDirection, iFloatBlockRow + 1, iFloatBlockCol))
{
iFloatBlockRow++;
}
else //不能往下落时就嵌入它
{
if (iFloatBlockRow + iBlockMaxRow[iCurrentBlock][iCurrentBlockDirection] <= 4)
{
//游戏结束
break;
}
CaptureFloatBlock();
ClearLine();
DrwaInfo();
GenerateNextBlock();
InitFloatBlockStarRC();
GetFloatBlock();
}
iWaitTime = 0;
}
cleardevice();
DrawGrid();//绘画网格
DrawFloatBlock();//绘画浮动方块
DrwaInfo();
FlushBatchDraw();
Sleep(SINGLE_DELAY);
iWaitTime += SINGLE_DELAY;
}
mciSendStringW(L"close bgm", NULL, 0, NULL);
SaveScore();//游戏结束,保存成绩
cleardevice();
int iStartX = (GRID_WIDTH * SLIDER_PX + INFO_WINDOW_WIDTH - 150) / 2;
int iStartY = ((GRID_HIGHT - 4) * SLIDER_PX-70)/2;
settextstyle(36, 0, L"幼圆");
outtextxy(iStartX, iStartY,L"游戏结束");
settextstyle(24, 0, L"幼圆");
outtextxy(iStartX, iStartY+40,L"按任意键退出");
EndBatchDraw();
int iRet=getchar();
closegraph();
return 0;
}