上次讲到一些基本的类、操作函数、还有一些乱七八糟的变量的定义,这次我们来完成操作函数的实现!
1、将png贴图透明
void TransparentPNG(CImage *png)
{
for(int i = 0; i <png->GetWidth(); i++)
{
for(int j = 0; j <png->GetHeight(); j++)
{
unsigned char* pucColor = reinterpret_cast<unsigned char *>(png->GetPixelAddress(i , j));
pucColor[0] = pucColor[0] * pucColor[3] / 255;
pucColor[1] = pucColor[1] * pucColor[3] / 255;
pucColor[2] = pucColor[2] * pucColor[3] / 255;
}
}
}
2、随机产生方块的颜色
void CChildView::DrawBlock(int flag)
{
for(int c=0;c<4;c++)
{
int i=rand()%colorKind; //颜色挑一种
block.eachPane[c].imageKind=i;
}
}
3、随机产生方块的形状
void CChildView::GenerateBlock(struct Block &blk)
{
int sel=rand()%7;
switch(sel)
{
case 0://田
blk.eachPane[0].x=4;
blk.eachPane[0].y=0;
blk.eachPane[1].x=5;
blk.eachPane[1].y=0;
blk.eachPane[2].x=4;
blk.eachPane[2].y=1;
blk.eachPane[3].x=5;
blk.eachPane[3].y=1;
blk.x1=blk.eachPane[0].x;
blk.x2=blk.eachPane[3].x;
blk.y1=blk.eachPane[0].y;
blk.y2=blk.eachPane[3].y;
break;
case 1://一
blk.eachPane[0].x=3;
blk.eachPane[0].y=0;
blk.eachPane[1].x=4;
blk.eachPane[1].y=0;
blk.eachPane[2].x=5;
blk.eachPane[2].y=0;
blk.eachPane[3].x=6;
blk.eachPane[3].y=0;
blk.x1=blk.eachPane[0].x;
blk.x2=blk.eachPane[3].x;
blk.y1=blk.eachPane[0].y;
blk.y2=blk.eachPane[3].y;
break;
case 2://L
blk.eachPane[0].x=4;
blk.eachPane[0].y=0;
blk.eachPane[1].x=4;
blk.eachPane[1].y=1;
blk.eachPane[2].x=4;
blk.eachPane[2].y=2;
blk.eachPane[3].x=5;
blk.eachPane[3].y=2;
blk.x1=blk.eachPane[0].x;
blk.x2=blk.eachPane[3].x;
blk.y1=blk.eachPane[0].y;
blk.y2=blk.eachPane[3].y;
break;
case 3://J
blk.eachPane[0].x=4;
blk.eachPane[0].y=0;
blk.eachPane[1].x=4;
blk.eachPane[1].y=1;
blk.eachPane[2].x=5;
blk.eachPane[2].y=1;
blk.eachPane[3].x=6;
blk.eachPane[3].y=1;
blk.x1=blk.eachPane[0].x;
blk.x2=blk.eachPane[3].x;
blk.y1=blk.eachPane[0].y;
blk.y2=blk.eachPane[3].y;
break;
case 4://Z
blk.eachPane[0].x=4;
blk.eachPane[0].y=0;
blk.eachPane[1].x=5;
blk.eachPane[1].y=0;
blk.eachPane[2].x=5;
blk.eachPane[2].y=1;
blk.eachPane[3].x=6;
blk.eachPane[3].y=1;
blk.x1=blk.eachPane[0].x;
blk.x2=blk.eachPane[3].x;
blk.y1=blk.eachPane[0].y;
blk.y2=blk.eachPane[3].y;
break;
case 5://反z
blk.eachPane[0].x=4;
blk.eachPane[0].y=0;
blk.eachPane[1].x=4;
blk.eachPane[1].y=1;
blk.eachPane[2].x=5;
blk.eachPane[2].y=1;
blk.eachPane[3].x=5;
blk.eachPane[3].y=2;
blk.x1=blk.eachPane[0].x;
blk.x2=blk.eachPane[3].x;
blk.y1=blk.eachPane[0].y;
blk.y2=blk.eachPane[3].y;
break;
case 6://T
blk.eachPane[0].x=4;
blk.eachPane[0].y=1;
blk.eachPane[1].x=5;
blk.eachPane[1].y=1;
blk.eachPane[2].x=5;
blk.eachPane[2].y=0;
blk.eachPane[3].x=6;
blk.eachPane[3].y=1;
blk.x1=blk.eachPane[0].x;
blk.x2=blk.eachPane[3].x;
blk.y1=blk.eachPane[2].y;
blk.y2=blk.eachPane[3].y;
break;
}
}
4、更新方块block的上下左右边界
void CChildView::UpdateLimit(struct Block &blk)
{
blk.x1 = blk.eachPane[0].x;
blk.x2 = blk.eachPane[0].x;
blk.y1 = blk.eachPane[0].y;
blk.y2 = blk.eachPane[0].y;
for (int i = 1; i < 4; i++)
{
if (blk.x1 > blk.eachPane[i].x)
{
blk.x1 = blk.eachPane[i].x;
}
if (blk.x2 < blk.eachPane[i].x)
{
blk.x2 = blk.eachPane[i].x;
}
if (blk.y1 > blk.eachPane[i].y)
{
blk.y1 = blk.eachPane[i].y;
}
if (blk.y2 < blk.eachPane[i].y)
{
blk.y2 = blk.eachPane[i].y;
}
}
}
5、对方块block进行变形
void CChildView::TransBlockForm()
{
//struct Block COPY=block;
int x1 = block.x1;
int x2 = block.x2;
int y1 = block.y1;
int y2 = block.y2;
if(x2-x1==y2-y1) //方块为正方形
return;
// 变形实现,对4个小方格依次判断重新设定位置
const int centx = (x1+x2)/2;
const int centy = (y1+y2)/2;
for(int i=0;i<4;i++)
{
int &x=block.eachPane[i].x;
int &y=block.eachPane[i].y;
if(x==centx&&y==centy) continue; // 中心方块不旋转
int detx=x-centx;
int dety=y-centy;
if(detx>0) //在中心方块右边
{
if(dety==0)//正右方---正下方
{
y = centy+detx;
x = centx;
}
else if(dety<0) //右上方--->右下方,列不变
{
y = centy-dety;
}
else //右下方--->左下方
{
x = centx-detx;
}
}
else if(detx<0)//在中心方块右边
{
if(dety==0)//正左方--->正上方
{
y = centy+detx;
x = centx;
}
else if(dety<0) //左上方--->右上方,行不变
{
x = centx-detx;
}
else //左下方--->左上方,列不变
{
y = centy-dety;
}
}
else //与中心点在同列
{
y = centy-detx;
x = centx-dety;
}
if(x<0||x>=10||(y>=0)&&gameAreas[y][x].bSet)//变形失败
{
//block=COPY;
TRACE("变形失败\n");
return;
}
}
TimesTransform++;
if (TimesTransform == 2) // 连续变形了两次
{
Move(RIGHT); // 右移一个单位
TimesTransform = 0;
}
UpdateLimit(block); // 更新方块的边界
return;
}
6、对block进行移动
//对block进行移动
void CChildView::Move(int direction)
{
switch(direction)
{
case LEFT:
case RIGHT:
if(block.x1+direction<0||block.x2+direction>9) break;
if(gameAreas[block.y1][block.x1+direction].bSet||gameAreas[block.y1][block.x2+direction].bSet||gameAreas[block.y2][block.x1+direction].bSet||gameAreas[block.y2][block.x2+direction].bSet) break;
for(int i =0;i<4;i++)
{
block.eachPane[i].x+=direction;
}
block.x1+=direction;
block.x2+=direction;
break;
}
}
7、block下降
void CChildView::MoveDown()
{
if(IsBorder())//到底了或是下方有物体
{
SetBlockFlag();
IsLine(); //是否满足消去条件
if(block.y1==0)
GameOver();
DrawBlock(flag);
GenerateBlock(block);
TimesTransform=0;
Invalidate();
return;
}
for(int c=0;c<4;c++)
{
block.eachPane[c].y+=1;
}
block.y1+=1;
block.y2+=1;
Invalidate();
return;
}
8、判断是否满足消去条件
bool CChildView::IsLine()
{
int u=block.y1;
//int tupLine = AreasTopLine;
for(int e = block.y2;e >= u;)
{
int k = 0;
for(k;k < 10; k++)
{
if(!gameAreas[e][k].bSet)
break;
}
if(k==10)
{
for(int t = e;t >= AreasTopLine;t--)
{
for(int r = 0;r <10;r++)
{
gameAreas[t][r].bSet = gameAreas[t-1][r].bSet;
gameAreas[t][r].blockkind = gameAreas[t-1][r].blockkind;
}
}
for(e = 0;e < 10;e++)
{
gameAreas[AreasTopLine][e].bSet = FALSE;
}
score += 100;
AreasTopLine++;
u++;
}
else
e--;
}
return FALSE;
}
9、判断是否到底
bool CChildView::IsBorder()
{
if(block.y2>=17) //到底
return TRUE;
for(int c=0;c<4;c++) //左、右、下方是否有物体
{
int i= block.eachPane[c].x;
int j= block.eachPane[c].y;
if(i>=0&&j>=0&&gameAreas[j+1][i].bSet)
return TRUE;
}
return FALSE;
}
10、标记gameAreas
void CChildView::SetBlockFlag()
{
TRACE("---------------------SETBLICKFLAG------------------\n");
if(AreasTopLine > block.y1)
{
AreasTopLine=block.y1; //记录最高一行
TRACE("记录最高一行:topline=%d\n",AreasTopLine);
}
for(int c=0;c<4;c++)
{
int m=block.eachPane[c].x;
int n=block.eachPane[c].y;
int i=block.eachPane[c].imageKind;
gameAreas[n][m].bSet=TRUE; // 设置此处已经被占据
gameAreas[n][m].blockkind=i;
}
return;
}
10、初始化
void CChildView::Initialize()
{
srand((unsigned)time(0)+clock());
background.Load(_T("res\\background.png"));
GenerateBlock(block);
DrawBlock(flag);
for(int c=0;c<4;c++)
{
block.eachPane[c].blockPNG.Load(_T("res\\BLOCK.png"));
TransparentPNG(&block.eachPane[c].blockPNG);
}
flag=1;
score=0;
AreasTopLine=17; //初始高度为1
for(int i=0;i<18;i++)
{
for(int j=0;j<10;j++)
{
gameAreas[i][j].bSet=FALSE;
gameAreas[i][j].blockPNG.Load(_T("res\\BLOCK.png"));
TransparentPNG(&gameAreas[i][j].blockPNG);
}
}
return;
}
11、游戏结束
void CChildView::GameOver()
{
KillTimer(TIMER_MOVE);
}
12、键盘响应
void CChildView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
switch (nChar)
{
case VK_UP:
TransBlockForm();//改变形状
Invalidate();
break;
case VK_LEFT:
Move(LEFT);//左移
Invalidate();
break;
case VK_RIGHT:
Move(RIGHT);//右移
Invalidate();
break;
case VK_DOWN:
MoveDown();//下降
Invalidate();
break;
}
return;
}
13、定时器
void CChildView::OnTimer(UINT_PTR nIDEvent)
{
switch(nIDEvent)
{
case TIMER_MOVE:
MoveDown();
break;
}
//CWnd::OnTimer(nIDEvent);
}

本文详细介绍了使用C++实现俄罗斯方块游戏的具体方法,包括方块的生成、移动、旋转等核心功能,并提供了完整的代码示例。
822

被折叠的 条评论
为什么被折叠?



