基于MFC的俄罗斯方块小游戏(二)

上次讲到一些基本的类、操作函数、还有一些乱七八糟的变量的定义,这次我们来完成操作函数的实现!

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);
}
  • 3
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值