一、前言
在之前一篇文章中,我们介绍了俄罗斯方块的其中一种数组点阵方阵算法,在本篇我们尝试换一种坐标算法来写同样的程序。所以预览效果也跟之前的没什么不同,就沿用之前的预览图了。
二、算法逻辑
其中大体逻辑跟上一篇大体一致,我们可以直接沿用之前的代码,只在方块数据表示及相关运算需要更改。
数据结构如下
struct _tagTetris
{
POINT ptBlock[4];
};
其中POINT结构是windows的系统结构,成员分别是int x 和int y。
四个数组成员代表了小方块的相对坐标,其中第一个数组成员(0,0)是当前方块中心点。所以之前的7个方块形状
可表示如下
//积木形状
tagTeris g_TetrsTemplate[] = {
{
{0,0,
-1,0, //****
1,0,
2,0} },
{ //***
{0,0, //*
1,0,
2,0,
0,1} },
{
{0,0,
-1,0, //***
1,0, // *
0,1} },
{
{0,0,
-2,0, //***
-1,0, // *
0,1} },
{
{0,0,
1,0, //**
0,1, //**
1,1} },
{
{0,0,
-1,0, //**
0,1, // **
1,1} },
{
{0,0,
1,0, // **
0,1, //**
-1,1}}
};
旋转算法则相对简单了,可以直接用旋转公式旋转90度来计算。
转左边
for(i=0;i<C_BLOCK_CNT;++i)
{
temp.ptBlock[i].x=g_TetrsRunning.ptBlock[i].y;
temp.ptBlock[i].y=-g_TetrsRunning.ptBlock[i].x;
}
转右边
for(i=0;i<C_BLOCK_CNT;++i)
{
temp.ptBlock[i].x=-g_TetrsRunning.ptBlock[i].y;
temp.ptBlock[i].y=g_TetrsRunning.ptBlock[i].x;
}
三、游戏主逻辑全部代码
游戏逻辑都在Tetris.h和Tetris.cpp文件中
Tetris.h
#ifndef _TETRIS_H
#define _TETRIS_H
#include "../import/include/SimpleCG.h"
#define C_IMAGE_BLOCK 20
#define C_MAP_WIDTH 10
#define C_MAP_HEIGHT 20
#define C_BLOCK_CNT 4
struct _tagTetris
{
POINT ptBlock[C_BLOCK_CNT];
};
typedef struct _tagTetris tagTeris;
int GetSpeed();
//初始化
void NewBlock();
//绘制单个方块
void DrawBlock( int nX, int nY, COLORREF nColor );
//绘制背景
void DrawMapBack( );
//绘制界面
void RenderBack();
//绘制内容
void DrawMap( );
//绘制移动中方块
void DrawMovinggBlock( );
//转动左边
void TurnLeft();
//转动右边
void TurnRight();
//移动左边
void MoveLeft();
//移动右边
void MoveRight();
//获取方块最左最右位置
void GetCurLeftRight(tagTeris *pTest, int *pLeft, int *pRight);
//是否可以往左右移动
bool CanMovHor(int nStepX);
//是否可以往下移动
bool IsExisted(tagTeris *pTest);
//往下移动
bool MovingDown();
//清除
void ClearBlock();
//清除
void ClearLine(int nY);
#endif
Tetris.cpsip
#include "Tetris.h"
enum ENUM_MAPTYPE
{
enumMAPTYPE_NULL
, enumMAPTYPE_FIXBLOCK
, enumMAPTYPE_DEADBLOCK
};
int g_nMap[ C_MAP_WIDTH * C_MAP_HEIGHT] = {0};
int g_nXMapPos = 100;
int g_nYMapPos = 50;
//积木形状
tagTeris g_TetrsTemplate[] = {
{
{0,0,
-1,0, //****
1,0,
2,0} },
{ //***
{0,0, //*
1,0,
2,0,
0,1} },
{
{0,0,
-1,0, //***
1,0, // *
0,1} },
{
{0,0,
-2,0, //***
-1,0, // *
0,1} },
{
{0,0,
1,0, //**
0,1, //**
1,1} },
{
{0,0,
-1,0, //**
0,1, // **
1,1} },
{
{0,0,
1,0, // **
0,1, //**
-1,1}}
};
tagTeris g_TetrsRunning = {0};
int g_nMovingX = 0;
int g_nMovingY = 0;
tagTeris g_Next=g_TetrsTemplate[1];
int g_nColorBlockNext = RGB(rand()%255,rand()%255,rand()%255);
int g_nColorBlock = g_nColorBlockNext;
int g_nSpeed = 9;
int g_nScore = 0;
int GetSpeed()
{
return g_nSpeed;
}
//创建新的方块
void NewBlock()
{
g_TetrsRunning = g_Next;
int nCount = sizeof(g_TetrsTemplate)/sizeof(g_TetrsTemplate[0]);
g_Next = g_TetrsTemplate[rand()%nCount];
g_nColorBlock = g_nColorBlockNext;
g_nMovingY = 0;
g_nMovingX = 4;
g_nColorBlockNext = RGB(rand()%255,rand()%255,rand()%255);
g_nScore += 10;
}
//绘制单个方块,绝对坐标
void DrawBlockPos( int nX, int nY, COLORREF nColor )
{
setlinewidth(3);
setfillcolor(nColor);
setlinecolor(SCGSubColor(nColor,100));
fillrectangle( nX, nY, nX + C_IMAGE_BLOCK-3, nY + C_IMAGE_BLOCK-3);
setlinecolor(SCGAddColor(nColor,100));
line(nX, nY, nX + C_IMAGE_BLOCK-5,nY);
line(nX, nY, nX,nY + C_IMAGE_BLOCK-5);
}
//绘制单个方块,地图坐标
void DrawBlock( int nX, int nY, COLORREF nColor )
{
int nXPos = g_nXMapPos + nX*C_IMAGE_BLOCK + 2;
int nYPos = g_nYMapPos + nY*C_IMAGE_BLOCK;
DrawBlockPos(nXPos, nYPos,nColor);
}
//绘制形状方块,地图坐标
void DrawTerisBlock( tagTeris *pTetris, int nX, int nY, COLORREF nColor )
{
int i=0;
for(i=0;i<C_BLOCK_CNT;++i)
{
DrawBlock( nX + pTetris->ptBlock[i].x, pTetris->ptBlock[i].y + nY, nColor );
}
}
//绘制背景
void DrawMapBack( )
{
int i=0;
int x=0;
int y=0;
clearrectangle(g_nXMapPos+1,g_nYMapPos-1,g_nXMapPos+1+C_IMAGE_BLOCK*C_MAP_WIDTH, g_nYMapPos+C_IMAGE_BLOCK*C_MAP_HEIGHT);
clearrectangle(301,90,350+C_IMAGE_BLOCK*4, 240);
RenderBack();
DrawTerisBlock(&g_Next, 12, 3, g_nColorBlockNext);
outtextXY(350,80,_T("下一个"));
outtextXY(320,180,_T("当前级别"));
outtextXY(320,220,_T("当前分数"));
printfXY( 400, 220, _T("%d"), g_nScore );
printfXY( 400, 180, _T("%d"), 10 - g_nSpeed);
}
//绘制界面
void RenderBack()
{
setline(0, 1, 0);
line(g_nXMapPos,g_nYMapPos,g_nXMapPos,g_nYMapPos+C_IMAGE_BLOCK*C_MAP_HEIGHT);
line(g_nXMapPos+C_IMAGE_BLOCK*C_MAP_WIDTH,g_nYMapPos,g_nXMapPos+C_IMAGE_BLOCK*C_MAP_WIDTH,g_nYMapPos+C_IMAGE_BLOCK*C_MAP_HEIGHT);
line(g_nXMapPos,g_nYMapPos+C_IMAGE_BLOCK*C_MAP_HEIGHT,g_nXMapPos+C_IMAGE_BLOCK*C_MAP_WIDTH,g_nYMapPos+C_IMAGE_BLOCK*C_MAP_HEIGHT);
}
//绘制内容
void DrawMap( )
{
int i=0;
int j=0;
for(j=0;j<C_MAP_HEIGHT;++j)
{
for(i=0;i<C_MAP_WIDTH;++i)
{
switch( g_nMap[j*C_MAP_WIDTH+i] )
{
case enumMAPTYPE_FIXBLOCK:
DrawBlock( i, j, RGB(30,60,235) );
break;
case enumMAPTYPE_DEADBLOCK:
break;
}
}
}
}
//绘制移动中方块
void DrawMovinggBlock( )
{
DrawTerisBlock(&g_TetrsRunning, g_nMovingX, g_nMovingY, g_nColorBlock);
}
//转动左边
void TurnLeft()
{
tagTeris temp;
int i=0;
for(i=0;i<C_BLOCK_CNT;++i)
{
temp.ptBlock[i].x=g_TetrsRunning.ptBlock[i].y;
temp.ptBlock[i].y=-g_TetrsRunning.ptBlock[i].x;
}
if(!IsExisted(&temp))
return;
int nLeft = 0;
int nRight = 0;
GetCurLeftRight(&temp, &nLeft, &nRight);
if( nLeft<0 )
{
g_nMovingX -= nLeft;
}
if( nRight>=C_MAP_WIDTH )
{
g_nMovingX -= nRight - C_MAP_WIDTH + 1;
}
g_TetrsRunning = temp;
}
//转动右边
void TurnRight()
{
tagTeris temp;
int i=0;
for(i=0;i<C_BLOCK_CNT;++i)
{
temp.ptBlock[i].x=-g_TetrsRunning.ptBlock[i].y;
temp.ptBlock[i].y=g_TetrsRunning.ptBlock[i].x;
}
if(!IsExisted(&temp))
return;
int nLeft = 0;
int nRight = 0;
GetCurLeftRight(&temp, &nLeft, &nRight);
if( nLeft<0 )
{
g_nMovingX -= nLeft;
}
if( nRight>=C_MAP_WIDTH )
{
g_nMovingX -= nRight - C_MAP_WIDTH + 1;
}
g_TetrsRunning = temp;
}
//移动左边
void MoveLeft()
{
if(CanMovHor(-1))
--g_nMovingX;
}
//移动右边
void MoveRight()
{
if(CanMovHor(1))
++g_nMovingX;
}
//获取方块最左位置
void GetCurLeftRight(tagTeris *pTest, int *pLeft, int *pRight)
{
int i=0;
int j=0;
*pLeft = 99;
*pRight = -1;
for(i=0;i<C_BLOCK_CNT;++i)
{
if( *pLeft>pTest->ptBlock[i].x + g_nMovingX )
*pLeft = pTest->ptBlock[i].x + g_nMovingX;
if( *pRight<pTest->ptBlock[i].x + g_nMovingX )
*pRight = pTest->ptBlock[i].x + g_nMovingX;
}
}
//是否可以往左右移动
bool CanMovHor(int nStepX)
{
int i=0;
int j=0;
for(i=0;i<C_BLOCK_CNT;++i)
{
int nX=g_TetrsRunning.ptBlock[i].x + g_nMovingX + nStepX;
int nY=g_TetrsRunning.ptBlock[i].y + g_nMovingY;
if(nX<0 || nX>=C_MAP_WIDTH )
return false;
if( g_nMap[nY*C_MAP_WIDTH+nX] != enumMAPTYPE_NULL )
return false;
};
return true;
}
//是否与原来方块冲突
bool IsExisted(tagTeris *pTest)
{
int i=0;
int j=0;
for(i=0;i<C_BLOCK_CNT;++i)
{
int nY=pTest->ptBlock[i].y + g_nMovingY + 1;
if( nY>=C_MAP_HEIGHT )
return false;
if( g_nMap[nY*C_MAP_WIDTH+pTest->ptBlock[i].x+g_nMovingX] )
return false;
}
return true;
}
//往下移动
bool MovingDown()
{
if(!IsExisted(&g_TetrsRunning))
{
int i=0;
int j=0;
for(i=0;i<C_BLOCK_CNT;++i)
{
int nY=g_TetrsRunning.ptBlock[i].y + g_nMovingY;
g_nMap[nY*C_MAP_WIDTH+g_TetrsRunning.ptBlock[i].x+g_nMovingX] = enumMAPTYPE_FIXBLOCK;
//测试是否结束
if(nY<=0)
{
outtextXY(200,20,_T("游戏结束"));
return false;
}
}
g_nMap[g_nMovingY*C_MAP_WIDTH+g_nMovingX] = enumMAPTYPE_FIXBLOCK;
NewBlock();
return false;
}
++g_nMovingY;
return true;
}
//清除
void ClearBlock()
{
int i=0;
int j=0;
bool bIsClear=true;
for(j=C_MAP_HEIGHT-1;j>=0;--j)
{
bIsClear=true;
for(i=0;i<C_MAP_WIDTH;++i)
{
if( g_nMap[j*C_MAP_WIDTH+i]==enumMAPTYPE_NULL )
{
bIsClear = false;
break;
}
}
if(bIsClear)
{
ClearLine(j);
g_nScore += 100;
if(g_nScore>=(10-g_nSpeed)*1000 && g_nSpeed>0)
--g_nSpeed;
++j;
}
}
}
//清除
void ClearLine(int nY)
{
int i=0;
int j=0;
for(j=nY;j>0;--j)
{
for(i=0;i<C_MAP_WIDTH;++i)
{
g_nMap[j*C_MAP_WIDTH+i]=g_nMap[(j-1)*C_MAP_WIDTH+i];
}
}
}
四、全部源代码
GameRussiaTetris2 · master · b2b160 / SimpleCG_Demo · GitCode
编译此程序需安装SimpleCG库,安装方法如下: