美文网首页
MFC实现2048小游戏

MFC实现2048小游戏

作者: downdemo | 来源:发表于2018-07-19 10:12 被阅读118次
    • 删除最初的static text框和两个button
    • 手动添加一个MyRect.h到头文件
    #include "stdafx.h"
    
    class MyRect
    {
    public:
        MyRect(UINT x1, UINT y1, UINT x2, UINT y2);
        ~MyRect();
    public:
        //矩形框的当前值
        UINT uValue;//矩形顶点坐标
        UINT x1;
        UINT y1;
        UINT x2;
        UINT y2;
    };
    
    • 手动添加一个MyRect.cpp到源文件
    #include "stdafx.h"
    #include "MyRect.h"
    
    MyRect::MyRect(UINT x1, UINT y1, UINT x2, UINT y2)
    {
        this->x1 = x1;
        this->y1 = y1;
        this->x2 = x2;
        this->y2 = y2;
        uValue = 0;
    }
    MyRect::~MyRect(){}
    
    • 在Dlg.cpp中添加包含头文件,并添加全局变量和函数
    #include "MyRect.h"
    
    #define LINELENGTH 4
    #define RECTNUM (LINELENGTH*LINELENGTH)
    
    struct MyPoint{
        int x;
        int y;
    };
    
    //实际矩形数组,面板上显示的每个矩形都是CRect类型,声明在这里
    CRect *rect[LINELENGTH][LINELENGTH];
    
    //控制是否生成新数字,为true的时候说明有动作,就会生成新数字
    bool bHaveDoneSth;
    
    //端点位置
    MyPoint point[LINELENGTH][LINELENGTH] = { 0 };
    
    //矩形对象数组,相当于逻辑部分,保存矩形的显示值,坐标
    MyRect *myrect[LINELENGTH][LINELENGTH];
    
    //填充画刷,可以控制矩形填充不同的颜色
    CBrush *brush;
    
    //生成一个新数字,随机一个0-RECTNUM的整数,根据这个整数计算出二维数组的横坐标和竖坐标
    //  A/LINELENGTH 是横坐标, A%LINELENGTH 是竖坐标, 当生成的位置有值的时候,重新生成
    // 初始值为2, 可以再这里加控制生成2,或 4 。
    void GenerateNewNum()
    {
        srand(time(0));
        int A = rand() % RECTNUM;
        while (myrect[A / LINELENGTH][A%LINELENGTH]->uValue != 0)
        {
            A = rand() % RECTNUM;
        }
        myrect[A / LINELENGTH][A%LINELENGTH]->uValue = 2;
    }
    
    //判断游戏结束
    bool GameOver()
    {
        //如果有值为0 的矩形,则游戏肯定可以继续,所以直接返回false
        for (int i = 0; i < LINELENGTH; i++)
            for (int j = 0; j < LINELENGTH; j++)
            {
                if (myrect[i][j]->uValue == 0)
                    return false;
            }
        // 对每一行相邻的两个数,如果有相同的,那么游戏可以继续,返回false
        for (int i = 0; i < LINELENGTH; i++)
            for (int j = 0; j < LINELENGTH - 1; j++)
            {
                if (myrect[i][j]->uValue == myrect[i][j + 1]->uValue)
                    return false;
            }
    
        // 对每一列相邻的两个数,如果有相同的,那么游戏可以继续,返回false
        for (int j = 0; j < LINELENGTH; j++)
            for (int i = 0; i < LINELENGTH - 1; i++)
            {
                if (myrect[i][j]->uValue == myrect[i + 1][j]->uValue)
                    return false;
            }
        return true;
    }
    
    • 在Dlg::OnInitDialog()中添加初始化代码
        ::SetWindowPos(this->m_hWnd, HWND_BOTTOM, 0, 0, 25 + LINELENGTH * 100, 48 + LINELENGTH * 100, SWP_NOZORDER);
        //初始化每个矩形的左上角点的坐标
        for (int i = 0; i < LINELENGTH; i++)
        {
            for (int j = 0; j < LINELENGTH; j++)
            {
                point[i][j].x = j * 100 + 10;
                point[i][j].y = i * 100 + 10;
            }
        }
        //初始化矩形和填充画刷
        for (int i = 0; i < LINELENGTH; i++)
        {
            for (int j = 0; j < LINELENGTH; j++)
            {
                myrect[i][j] = new MyRect(point[i][j].x, point[i][j].y, point[i][j].x + 90, point[i][j].y + 90);
                myrect[i][j]->uValue = 0;
            }
        }
        //初始化数字
        srand(time(0));
        int A = rand() % RECTNUM;
        int B = rand() % RECTNUM;
        while (B == A)
        {
            B = rand() % RECTNUM;
        }
        myrect[A / LINELENGTH][A % LINELENGTH]->uValue = 2;
        myrect[B / LINELENGTH][B % LINELENGTH]->uValue = 2;
    
    • 在OnPaint()中添加绘制代码
        CFont font;
        font.CreateFont(25, 25, 0, 0, 700, false, false, false,
            CHINESEBIG5_CHARSET, OUT_CHARACTER_PRECIS,
            CLIP_CHARACTER_PRECIS, DEFAULT_QUALITY,
            FF_MODERN, TEXT("宋体"));
    
        //客户区设备环境
        CClientDC dc(this);
        //新建画笔
        CPen pen;
        pen.CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
        //选中字体
        dc.SelectObject(pen);
        for (int i = 0; i < LINELENGTH; i++)
        {
            for (int j = 0; j < LINELENGTH; j++)
            {
                //画矩形
                //dc.RoundRect(myrect[i][j]->getRect(), 4, 4);
                dc.Rectangle(myrect[i][j]->x1, myrect[i][j]->y1, myrect[i][j]->x2, myrect[i][j]->y2);
                //填充矩形
                rect[i][j] = new CRect(myrect[i][j]->x1, myrect[i][j]->y1, myrect[i][j]->x2, myrect[i][j]->y2);
    
                //设置文字背景透明
                dc.SetBkMode(TRANSPARENT);
                //选中字体
                dc.SelectObject(font);
                //写数字
                if (myrect[i][j]->uValue == 0)
                {
                    brush = new CBrush(RGB(0xFC, 0xFC, 0xFC));
                    dc.FillRect(rect[i][j], brush);
                    delete brush;
                }
                else if (myrect[i][j]->uValue != 0)
                {
                    switch (myrect[i][j]->uValue)
                    {
                    case 2:brush = new CBrush(RGB(0xFF, 0xFF, 0xFF)); break;
                    case 4:brush = new CBrush(RGB(0xFF, 0xE4, 0xC4)); break;
                    case 8:brush = new CBrush(RGB(0xFF, 0xB6, 0xC1)); break;
                    case 16:brush = new CBrush(RGB(0xFF, 0x83, 0xFA)); break;
                    case 32:brush = new CBrush(RGB(0xFF, 0xC1, 0x25)); break;
                    case 64:brush = new CBrush(RGB(0xFF, 0x6A, 0x6A)); break;
                    case 128:brush = new CBrush(RGB(0xFF, 0x14, 0x93)); break;
                    case 256:brush = new CBrush(RGB(0xCD, 0x66, 0x1D)); break;
                    case 512:brush = new CBrush(RGB(0x94, 0x00, 0xD3)); break;
                    case 1024:brush = new CBrush(RGB(0xFF, 0xFF, 0x00)); break;
                    case 2048:brush = new CBrush(RGB(0xFF, 0x00, 0x00)); break;
                    default:brush = new CBrush(RGB(0xFF, 0x00, 0x00)); break;
                    }
                    dc.FillRect(rect[i][j], brush);
                    delete brush;
                    CString str;
                    str.Format(_T("%d"), myrect[i][j]->uValue);
                    dc.DrawText(str, rect[i][j], DT_VCENTER | DT_CENTER | DT_SINGLELINE);
                }
            }
        }
    
    • 为了让对话框直接捕获消息,重载PreTranslateMessage,重载前要在Dlg.h中给Dlg类添加声明virtual BOOL PreTranslateMessage(MSG* pMsg);
    BOOL CMy3Dlg::PreTranslateMessage(MSG* pMsg)
    {
        // TODO: Add your specialized code here and/or call the base class
        if (pMsg->message == WM_KEYUP)
        {
            switch (pMsg->wParam)
            {
            case VK_LEFT:
                //判断是否有动作,用来控制是否生成新数字
                bHaveDoneSth = false;
                for (int i = 0; i < LINELENGTH; i++)
                {
    
                    //去掉空格
                    for (int j = 0; j < LINELENGTH; j++)
                    {
                        //
                        if (myrect[i][j]->uValue != 0)
                        {
                            for (int k = 0; k < j; k++)
                            {
                                if (myrect[i][k]->uValue == 0)
                                {
                                    bHaveDoneSth = true;
                                    myrect[i][k]->uValue = myrect[i][j]->uValue;
                                    myrect[i][j]->uValue = 0;
                                    break;
                                }
                            }
                        }
                    }
    
                    //相加
                    for (int j = 0; j < LINELENGTH - 1; j++)
                    {
                        if (myrect[i][j]->uValue != 0)
                        {
                            if (myrect[i][j + 1]->uValue == myrect[i][j]->uValue)
                            {
                                bHaveDoneSth = true;
                                myrect[i][j]->uValue += myrect[i][j + 1]->uValue;
                                myrect[i][j + 1]->uValue = 0;
                            }
                        }
                    }
    
                    //去掉空格
                    for (int j = 0; j < LINELENGTH; j++)
                    {
                        if (myrect[i][j]->uValue != 0)
                        {
                            for (int k = 0; k < j; k++)
                            {
                                if (myrect[i][k]->uValue == 0)
                                {
                                    bHaveDoneSth = true;
                                    myrect[i][k]->uValue = myrect[i][j]->uValue;
                                    myrect[i][j]->uValue = 0;
                                    break;
                                }
                            }
                        }
                    }
                }
                break;
            case VK_UP:
                bHaveDoneSth = false;
                for (int j = 0; j < LINELENGTH; j++)
                {
                    //去掉空格
                    for (int i = 0; i < LINELENGTH; i++)
                    {
                        //
                        if (myrect[i][j]->uValue != 0)
                        {
                            for (int k = 0; k < i; k++)
                            {
                                if (myrect[k][j]->uValue == 0)
                                {
                                    bHaveDoneSth = true;
                                    myrect[k][j]->uValue = myrect[i][j]->uValue;
                                    myrect[i][j]->uValue = 0;
                                    break;
                                }
                            }
                        }
                    }
    
                    //相加
                    for (int i = 0; i < LINELENGTH - 1; i++)
                    {
                        if (myrect[i][j]->uValue != 0)
                        {
                            if (myrect[i + 1][j]->uValue == myrect[i][j]->uValue)
                            {
                                bHaveDoneSth = true;
                                myrect[i][j]->uValue += myrect[i + 1][j]->uValue;
                                myrect[i + 1][j]->uValue = 0;
                            }
                        }
                    }
    
                    //去掉空格
                    for (int i = 0; i < LINELENGTH; i++)
                    {
                        //
                        if (myrect[i][j]->uValue != 0)
                        {
                            for (int k = 0; k < i; k++)
                            {
                                if (myrect[k][j]->uValue == 0)
                                {
                                    bHaveDoneSth = true;
                                    myrect[k][j]->uValue = myrect[i][j]->uValue;
                                    myrect[i][j]->uValue = 0;
                                    break;
                                }
                            }
                        }
                    }
                }
    
                break;
            case VK_RIGHT:
                bHaveDoneSth = false;
                for (int i = 0; i < LINELENGTH; i++)
                {
                    //去掉空格
                    for (int j = LINELENGTH - 1; j >= 0; j--)
                    {
                        //
                        if (myrect[i][j]->uValue != 0)
                        {
                            for (int k = LINELENGTH - 1; k >= j; k--)
                            {
                                if (myrect[i][k]->uValue == 0)
                                {
                                    bHaveDoneSth = true;
                                    myrect[i][k]->uValue = myrect[i][j]->uValue;
                                    myrect[i][j]->uValue = 0;
                                    break;
                                }
                            }
                        }
                    }
    
                    //相加
                    for (int j = LINELENGTH - 1; j > 0; j--)
                    {
                        if (myrect[i][j]->uValue != 0)
                        {
                            if (myrect[i][j - 1]->uValue == myrect[i][j]->uValue)
                            {
                                bHaveDoneSth = true;
                                myrect[i][j]->uValue += myrect[i][j - 1]->uValue;
                                myrect[i][j - 1]->uValue = 0;
                            }
                        }
                    }
    
                    //去掉空格
                    for (int j = LINELENGTH - 1; j >= 0; j--)
                    {
                        //
                        if (myrect[i][j]->uValue != 0)
                        {
                            for (int k = LINELENGTH - 1; k >= j; k--)
                            {
                                if (myrect[i][k]->uValue == 0)
                                {
                                    bHaveDoneSth = true;
                                    myrect[i][k]->uValue = myrect[i][j]->uValue;
                                    myrect[i][j]->uValue = 0;
                                    break;
                                }
                            }
                        }
                    }
                }
    
                break;
            case VK_DOWN:
                bHaveDoneSth = false;
                for (int j = LINELENGTH - 1; j >= 0; j--)
                {
    
                    //去掉空格
                    for (int i = LINELENGTH - 1; i >= 0; i--)
                    {
                        //
                        if (myrect[i][j]->uValue != 0)
                        {
                            for (int k = LINELENGTH - 1; k >= i; k--)
                            {
                                if (myrect[k][j]->uValue == 0)
                                {
                                    bHaveDoneSth = true;
                                    myrect[k][j]->uValue = myrect[i][j]->uValue;
                                    myrect[i][j]->uValue = 0;
                                    break;
                                }
                            }
                        }
                    }
    
                    //相加
                    for (int i = LINELENGTH - 1; i > 0; i--)
                    {
                        if (myrect[i][j]->uValue != 0)
                        {
                            if (myrect[i - 1][j]->uValue == myrect[i][j]->uValue)
                            {
                                bHaveDoneSth = true;
                                myrect[i][j]->uValue += myrect[i - 1][j]->uValue;
                                myrect[i - 1][j]->uValue = 0;
                            }
                        }
                    }
    
                    //去掉空格
                    for (int i = LINELENGTH - 1; i >= 0; i--)
                    {
                        //
                        if (myrect[i][j]->uValue != 0)
                        {
                            for (int k = LINELENGTH - 1; k >= i; k--)
                            {
                                if (myrect[k][j]->uValue == 0)
                                {
                                    bHaveDoneSth = true;
                                    myrect[k][j]->uValue = myrect[i][j]->uValue;
                                    myrect[i][j]->uValue = 0;
                                    break;
                                }
                            }
                        }
                    }
                }
    
                break;
            default:
                break;
            }
    
            if (bHaveDoneSth)
            {
                GenerateNewNum();
            }
    
            Invalidate(FALSE);
            if (GameOver())
            {
                MessageBox(_T("游戏结束!"));
            };
        }
        return CDialog::PreTranslateMessage(pMsg);
    }
    

    MFC对话框无法响应键盘按键

    • 给类添加一个WM_KEYUP的消息,运行时不会响应键盘,原因是控件需要首先对按键作出响应,比如多行编辑框会先处理回车防止回车关闭对话框。要直接让对话框响应按键,方法是重载PreTranslateMessage改变消息控制流程
    • 让对话框直接捕获消息
    BOOL CMy3Dlg::PreTranslateMessage(MSG* pMsg)
    {
        if (pMsg->message == WM_KEYUP)
        {
            switch (pMsg->wParam)
            {
                case VK_LEFT: ...; break;
                case VK_UP: ...; break;
                case VK_RIGHT: ...; break;
                case VK_DOWN: ...; break;
                default: break;
            }
        }
        return CDialog::PreTranslateMessage(pMsg);
    }
    
    • 或者实现当按下方向键时调用OnKeyUp
    BOOL CSampleControl::PreTranslateMessage(LPMSG lpmsg)
    {
        BOOL bHandleNow = FALSE;
        switch (lpmsg->message)
        {
            case WM_KEYUP:
            switch (lpmsg->wParam)
            {
                case VK_UP:
                case VK_DOWN:
                case VK_LEFT:
                case VK_RIGHT:
                bHandleNow = TRUE;
                break;
            }
            if (bHandleNow)
            OnKeyUp(lpmsg->wParam, LOWORD(lpmsg ->lParam), HIWORD(lpmsg->lParam));
            break;
        }
        return bHandleNow;
    }
    

    相关文章

      网友评论

          本文标题:MFC实现2048小游戏

          本文链接:https://www.haomeiwen.com/subject/gebzpftx.html