2048_Finish_report


2048游戏及管理平台

一、项目内容

1.需求分析

1.1 设计目标

1、基本要求:

(1)布设游戏的场景;
(2)管理游戏的玩家,包括记录并显示玩家的用户名、实时排名以及得分,游戏过程中的记录信息包括玩家操作等;
(3)按规则执行游戏过程,判定游戏胜利;
(4)记录游戏过程包括玩家操作以及每一步操作的结果,并可以通过图形界面演示重现;
(5)游戏规则:每次可以选择上下左右其中一个方向去滑动,每滑动一次,所有的数字方块都会往滑动的方向靠拢外,系统也会在空白的地方乱数出现一个数字方块,相同数字的方块在靠拢、相撞时会相加。系统给予的数字方块不是2就是4,玩家要想办法在这小小的16格范围中凑出“2048”这个数字方块;
(6)矩阵的四周有四个按钮,分别表示向左、向右、向上、向下移动。当某一方向无法移动时,该按钮应该被隐藏(变灰)。

2、发挥部分:

(1)限定游戏时间:在游戏界面添加倒计时,并设计倒计时程序。当计时到时游戏结束并重置界面;
(2)添加背景音乐;
(3)增加滚动字幕,字幕内容为一些名人名言,提升游戏过程中的趣味性;
(4)在演示玩家操作时,用户可选择演示播放速度,以满足用户不同需求;
(5)实现数据可迁移,方便用户在不同PC设备上使用;
(6)添加用户登录界面,方便对玩家的管理;
(7)在游戏界面添加时间日期显示,显示当前的日期和时间;
(8)添加键盘控制功能,玩家可以通过键盘控制界面上下左右操作。

1.2 功能需求

(1)用户登录:打开游戏程序后,用户在用户名输入框输入用户名即可进入游戏。
(2)开始游戏:游戏界面左上角显示游戏倒计时,用户应在倒计时结束前使游戏面盘内的数字尽可能大。用户可以通过鼠标点击界面的四个方向按钮或者键盘的上下左右键进行操作。当倒计时间到或者游戏无法继续进行时,将弹出“Game Over!”提示信息。
(3)退出登录:当用户想要切换登录账户或者退出游戏时,可以点击界面右下角的“退出登陆”按键,游戏将返回登陆界面,同时正在进行的游戏将中断。
(4)排行榜:游戏界面右侧文本框显示游戏玩家实时排名。若用户需要刷新排名,可点击右上角“刷新”按键。
(5)回放按键:若用户需要回访排行榜内玩家游戏过程,可先在右下角下拉文本框内选择要观看的玩家排名,后点击“观看”按键。之后玩家在弹出的对话框内选择倍速播放的速度,游戏面盘内会按照设定倍速演示游戏过程。演示结束后,游戏面盘会重置,回到游戏。

(6)其他功能:
 当前时间显示:游戏界面左下角显示当前日期和时间,方便用户管理游戏时间;
 名人名言:游戏界面中下部滚动显示名人名言,在游戏过程中增添了文化氛围;
 背景音乐:游戏运行过程中会有舒缓的轻音乐作为背景音乐,使用户在游戏过程中保持平静和放松的心情;
 操作记录:游戏界面中部文本框内显示用户登录信息和实时操作,方便用户查看与记录。

1.3 假定和约束

(1)假定用户在输入用户名等信息后,不使用Enter健输入,而是点击确定按钮。并且假定用户在整个游戏过程中不使用Enter键。因为当用户按下Enter键时,Windows就会自动去找输入焦点落在了哪一个按钮上,当获得焦点的按钮的四周将被点线矩形包围。如果所有按钮都没有获得输入焦点,Windows就会自动去寻找程序或资源所指定的默认按钮(默认按钮边框较粗)。如果对话框没有默认按钮,那么即使对话框中没有OK按钮,OnOK函数也会自动被调用。在本游戏中,OnOK函数内并没有响应,如果用户按下Enter,会导致游戏直接关闭。
(2)假定用户在观看回放的过程中,不进行其它操作。因为在程序中,当开始观看时,其它功能会被锁定,无法正常运行。
(3)假定用户在使用过程中,不会修改游戏的数据文件。因为游戏中的排名信息以及操作数据是读取自这些数据文件。

2.结构设计

image-20210407205829752

表1:各模块名称及其作用

名称 功能
用户名输入模块 使玩家能够输入用户名,并将输入的用户名存储以便后续的调用
对话框初始化模块 初始化正式游戏界面,包括绘制面板、消息映射等
定时器模块 配置定时器,向倒计时、当前时间显示和名人名言滚动显示等功能提供统一的时间和频率
操作模块 配置键盘方向键和四个方向按钮,并对其消息进行拦截和处理,使玩家能通过界面按键和键盘进行控制
计算模块 每进行一次操作,对游戏面盘内的数字进行计算
操作实时显示模块 在界面文本框内实时显示用户登录信息和操作信息
文件读写模块 将用户的基本信息和操作信息通过文件形式存储在硬盘,并且实时更新。在需要时进行读取。
排行榜模块 利用所存储的信息,对所有玩家进行排序,并在界面文本框内实时显示玩家排名
观看模块 对高分玩家的游戏过程进行回放,用户可以自行选择播放速度
退出登录模块 用于切换用户或结束游戏

image-20210407210510889

3.详细设计

3.1 工程建立

  1. 打开Visual Studio2017,点击文件——新建——项目;

  2. 新建MFC应用;

    image-20210407210621548

图3:新建项目界面
3. 选择“基于对话框”;

image-20210407210631868

图4:应用程序类型选项界面

  1. 点击“完成”即可建立工程。

3.2 界面设计

  1. 打开创建的工程文件,选择资源视图,打开对话框界面;

    image-20210407210722995

图5:对话框初始界面
2. 将所需的控件拖入对话框并放置在合适的位置;

image-20210407210731733

图6:完成后的对话框界面
3. 再次打开资源视图,创建新的对话框界面为欢迎界面

image-20210407210739776

图7:新建对话框界面操作
4. 向新建的对话框界面添加控件

image-20210407210748103

图8:完成后的欢迎界面
5. 最后,通过On_Paint 函数对窗口进一步美化,配置字体.背景.窗口大小等,并绘制游戏面盘;

image-20210407210759280

图9:OnPaint函数部分代码

3.3 用户名输入模块设计

  1. 从“资源视图”打开欢迎界面,放置用于用户输入的文本框;

    image-20210407210822757

图10:用户名输入框
2. 当按下欢迎界面的确定按钮时,对文本框内文字进行处理。因此在“确定”按钮的响应函数内,首先检测文本框内是否有内容,然后将用户名转存至新建的游戏界面类成员内,之后使用EndDialog函数与DoModal函数打开游戏界面,关闭欢迎界面;

image-20210407210830670

图11:确定按键响应函数

3.4 定时器模块设计

  1. 首先使用类向导,为游戏程序添加WM_TIMER消息映射,并生成OnTimer处理函数;

    image-20210407210907203

图12:类向导界面
2. 在初始化函数OnInitDialog中配置两个定时器的编号和定时间隔;

image-20210407210917559

图13:配置定时器代码
3. 在生成的OnTimer处理函数中,添加倒计时.显示当前时间以及名人名言滚动显示的代码。通过对nIDEvent变量的判断,为不同的功能选择不同的时间频率;

image-20210407210927767

图14:OnTimer函数部分代码

3.4 操作模块设计

  1. 在游戏中玩家可通过键盘或鼠标点击按钮来操作游戏;

  2. 键盘操作:通过重载虚函数PreTranslateMessage()对键盘上下左右键进行截取与响应;

    image-20210407210955093

图15:PreTranslateMessage函数的部分代码
3. 鼠标操作:在“资源视图”打开游戏界面对话框,添加四个按钮,表示上下左右,并放置在合适位置,之后在其响应函数中写入相应程序;

image-20210407211002388

图16:“↑”按钮响应函数

3.5计算模块设计

image-20210407211013036

  1. 累加函数

    image-20210407211057117

图17:累加函数部分代码
2. 处理游戏结束:横轴.纵轴分别判断游戏是否能够继续进行。供其它操作函数调用;

image-20210407211106277

图18:处理游戏结束函数部分代码
3. 上下左右计算:调用累加函数,循环输出后检测变动,判断此方向能否继续移动。若不能,则将对应按钮置灰。

image-20210407211114589

图19:向上计算函数部分代码

3.6界面重置模块设计

被调用时,将界面清零,并随机生成数值,输出到游戏面盘。之后将游戏结束的信息记录在相应的数据文件内。

image-20210407211236989

图20:重置函数部分代码

3.7文件写入模块设计

  1. 使用CStdioFile标准库函数进行文件读写操作,供其它操作函数调用;

  2. 文件读取部分未集成未模块,相应代码在之后的排行榜及观看模块中均有体现;

    image-20210407211302714

图21:文件写入函数

3.8排行榜模块设计

  1. 创建用户类:其中MAX为用户得分,order为用户在数据文件中所处的位置;

    image-20210407211327374

图22:用户类
2. 使用ReadString函数读取文件,用读取到的信息对用户类对象赋值,使用CArray标准库实现追加;

image-20210407211333706

图23:读取和追加部分代码
3. 使用交换排序算法对CArray类对象进行排序,并以一定格式输出到文本框控件;

image-20210407211342524

图24:排序与输出功能代码

3.9观看模块设计

  1. 在“资源视图”,放置下拉文本框控件在游戏界面,并添加“观看”按钮;

    image-20210407211419417

图25:观看功能相关控件
2. 当玩家按下“观看”按钮时,其响应函数被调用,将布尔型全局变量wop变为FALSE,开启“观看模式”。此时,倒计时停止,玩家操作鼠标或键盘将无效。同时,调用DoModal函数,弹出播放速度选择对话框;

image-20210407211427250

图26:“观看”按钮响应函数部分代码

image-20210407211433715

图27:播放速度选择界面
3. 根据用户在文本框内所选的玩家信息,在操作数据文件中根据玩家的order成员变量寻找该玩家,找到后将记录的操作信息依次输出至游戏面盘。
4. 输出结束后,将变量wop变为TRUE,关闭“观看模式”,玩家继续游戏。

3.10退出登录模块设计

用户点击“退出登陆”按钮时,调用EndDialog函数,关闭游戏界面。之后调用DoModal函数,生成新的欢迎界面。

4.运行结果与分析

4.1 用户登录功能

image-20210407211514579

图28:用户登录界面

4.2 基础功能(游戏功能)

image-20210407211538492

图29:鼠标与键盘操作游戏

image-20210407211544421

图30:当一个方向无法移动时,按钮置灰

image-20210407211549984

图31:当所有方向都无法移动时,游戏结束

4.3当前时间显示功能

image-20210407211612733

图32:显示当前日期与时间

4.4登录信息及实时操作显示功能

image-20210407211635812

图33:显示玩家登录信息及操作

4.5排行榜功能

image-20210407211649803

图34:对所有玩家进行排序(最多显示TOP15)

4.6观看功能

image-20210407211658280

图35:下拉文本框与“观看”按键

image-20210407211729265

图36:播放速度选择对话框

image-20210407211734856

图37:正在观看中

4.7名人名言显示功能

image-20210407211750332

图38:文本框内滚动显示名人名言

4.8背景音乐功能

经测试游戏运行中有背景音乐播放

4.9退出登录功能

image-20210407211815174

图39:点击“退出登录”后返回欢迎界面

二、问题解决

(1)在程序设计过程中,你是否通过自定义类对某些功能进行了封装?这些类主要的功能是什么?

答:①usr类:表示一个用户的类。成员变量:name——用户名;MAX——得分;order——用户信息在数据文件中的位置。
②RandonNum成员函数:无形参,无返回值。随机生成数字2或4,并将其放在游戏面盘的随机位置。
③CalcEnd成员函数:无形参,返回BOOL型。判断横轴与纵轴能否继续移动。若能移动,则继续游戏;否则,游戏结束。
④reALLBUTTON成员函数:无形参,无返回值。重置四个方向按钮。
⑤WriteTXT成员函数:形参CString型,无返回值。向指定文件写入字符串。
⑥TravelArrey成员函数:无形参,返回CString型。遍历游戏面盘,并将数据以CString类型返回。
⑦TOPList成员函数:无形参,无返回值。将排行榜功能所需的遍历.排序以及输出集成在此函数中。
⑧watch成员函数:形参int型,无返回值。完成观看功能,包括查找.遍历.文件读取以及输出。

(2)小结上机各个环节所出现的错误及解决的办法。

答:
错误一:定时器相关函数不被执行。
解决方法:通过手动输入的配置定时器的代码,即使内容一致,也无法运行。应该通过类向导,加入定时器的消息映射WM_TIMER,程序在执行定时器相关函数。
错误二:调用CString类的Format函数时,报错“没有与参数列表匹配的重载函数”。
解决方法:Format函数的形参之一为LPCWSTR类型变量,与字符串的char类型不相符。因此将需要格式化的字符串通过_T函数转换。
错误三:点击“观看”按钮后,本应弹出选择播放速度对话框,但实际情况为界面卡死,无法操作。
解决方法:在资源视图中打开要弹出的对话框,将属性中的Visable选项更改为TRUE即可。

三、主要代码

1.登陆函数

void CStartDlg::OnBnClickedStartButton()
{
    CString str;
    //BOOL c;
    //EndDialog(IDD_START_DIALOG);
    CMy2048Dlg dlg;
    GetDlgItem(IDC_EDIT1)->GetWindowText(str);
    //CEdit1.GetWindowText();
        if (str != "")//判断用户是否输入
        {
            EndDialog(IDD_START_DIALOG);//关闭登陆界面
            dlg.Userr.name = str;
            dlg.DoModal();//调出游戏界面
        }
        else
        {
            AfxMessageBox(_T("请输入用户名"));//提醒用户重新输入
        }
}

2.OnPaint函数

void CMy2048Dlg::OnPaint()
{
    if (IsIconic())
    {
        CPaintDC dc(this); // 用于绘制的设备上下文
        SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
        // 使图标在工作区矩形中居中
        int cxIcon = GetSystemMetrics(SM_CXICON);
        int cyIcon = GetSystemMetrics(SM_CYICON);
        CRect rect;
        GetClientRect(&rect);
        int x = (rect.Width() - cxIcon + 1) / 2;
        int y = (rect.Height() - cyIcon + 1) / 2;
        // 绘制图标
        dc.DrawIcon(x, y, m_hIcon);
    &#125;
    else //初始化游戏面盘
    &#123;
        CRect   temprect(0, 0, 1000, 500);
        CWnd::SetWindowPos(NULL, 0, 0, temprect.Width(), temprect.Height(), SWP_NOZORDER | SWP_NOMOVE);
        CPaintDC dc(this);
        GetClientRect(rect);
        dc.FillSolidRect(rect, RGB(125, 255, 255)); //设置背景颜色
        GetClientRect(rect);
        //获取窗口客户区的坐标 客户区坐标是相对窗口客户区的左上角而言的,因此左上角坐标为(0,0)。
        rect.left   += 20;
        rect.right  -= 20;
        rect.top    += 20;
        rect.bottom -= 20;
        CRgn rgn;//圆角
        CRect rc;
        GetWindowRect(&rc); //获得窗口矩形
        rc -= rc.TopLeft();
        rgn.CreateRoundRectRgn(rc.left, rc.top, rc.right, rc.bottom, 50, 50); 
        //根据窗口矩形创建一个圆角矩形最后两个是形成圆角的大小
        SetWindowRgn(rgn, TRUE);
        int nWidth  = rect.Width()/(2*(Count+2)); //每个单元格的宽度
        int nHeight = rect.Height()/(Count+2);//每个单元格的高度
        CFont font;
        font.CreatePointFont(nHeight*4, _T("Small Fonts"),&dc); //创建字体和大小
        CFont* oldFont = dc.SelectObject(&font);//保存旧的字体
        dc.SetBkMode(TRANSPARENT);//设置背景颜色为透明
        for(int i = 0; i < Count; i++)
        &#123;
            for (int j = 0; j < Count; j++)
            &#123;
                CRect rectChild;
                rectChild.left   = rect.left + j*nWidth+ nWidth;
                rectChild.top    = rect.top  + i*nHeight+ nHeight;
                rectChild.right  = rectChild.left + nWidth;
                rectChild.bottom = rectChild.top  + nHeight;
                dc.Draw3dRect(rectChild,RGB(255,255,0),RGB(255,255,0));
                if (wop)
                &#123;
                    if (m_nArray[i][j] != 0)
                    &#123;
                        CString  strText;
                        strText.Format(_T("%d"), m_nArray[i][j]);
    //函数功能是在指定的矩形里写入格式化文本,根据指定的方法对文本格式化
                        //(扩展的制表符,字符对齐、折行等)
                        dc.DrawText(strText, rectChild, DT_CENTER | DT_VCENTER);
                    &#125;
                &#125;
                else if (!wop)
                &#123;
                    if (n_nArray[i][j] != 0)
                    &#123;
                        CString  strText;
                        strText.Format(_T("%d"), n_nArray[i][j]);

                        //该函数的功能是在指定的矩形里写入格式化文本,根据指定的方法对文本格式化
                        //(扩展的制表符,字符对齐、折行等)
                        dc.DrawText(strText, rectChild, DT_CENTER | DT_VCENTER);
                    &#125;
                &#125;
            &#125;
        &#125;
        CDialogEx::OnPaint();
        dc.SelectObject(oldFont);//选则回原来的字体
        font.DeleteObject();//删除字体
    &#125;
&#125;

3.重置界面函数

//重置,重新开始界面初始化
void CMy2048Dlg::Reset(void)
&#123;
    //int buff[4][4];
    int max = 0;
    for(int i = 0; i < Count; i++)
    &#123;
        for (int j = 0; j < Count; j++)
        &#123;
            m_nArray[i][j] = 0;
        &#125;
    &#125;
    ct = COUNT;
    RandonNum();
    RandonNum();
    CString strrrr;
    strrrr.Format(_T("u_%s\n"), Userr.name);
    WriteNameTXT(strrrr);
    strrrr.Format(_T("L_%s\n"), Userr.name);
    WriteTXT(strrrr);
    CString strr;
    strr = TravelArrey();
    WriteTXT(strr);
&#125;

4.向下运算函数

bool CMy2048Dlg::Down(void)
&#123;
    if(wop)
    &#123;
    int tempArray[Count][Count];
    memcpy(tempArray, m_nArray, sizeof(int)*Count*Count);
    reALLBUTTON();
    deque<int> lst[Count];//声明一个deque<int>类型的数组 数组长度为4,也就是4个deque<int>
    //分组
        for (int i = 0; i < Count; i++)
    &#123;
        for (int j = 0; j < Count; j++)
        &#123;
            if (m_nArray[i][j] != 0)
            &#123;
                lst[j].push_front(m_nArray[i][j]);
            &#125;
        &#125;
    &#125;
    //累加
    for (int i = 0; i < Count; i++)
    &#123;
        Add(lst[i]); 
//这里假设对于 lst[0];相加后为: lst[0][0]: 4; lst[0][1]:2;没有变化这种情况
//因为相加的时候是 以lst[0][0], lst[1][0]为基准,所以这里向下相加后,就要反转一下
        ReservedLst(lst[i]);
    &#125;
    //重新赋值
    for (int i = 0; i < Count; i++)
    &#123;
        for (int j = 0; j < Count; j++)
        &#123;
            m_nArray[i][j] = lst[j][i]; //注意这里是 lst[j][i] 赋值给 m_nArray[i][j]
        &#125;
    &#125;

    //检测变动
    for (int i = 0; i < Count; i++)
    &#123;
        for (int j = 0; j < Count; j++)
        &#123;
            if (m_nArray[i][j] != tempArray[i][j])
            &#123;
                return true;
            &#125;
        &#125;
    &#125;
    GetDlgItem(IDC_BUTTON4)->EnableWindow(FALSE);
    return false;
    &#125;return TRUE;
&#125;

5.游戏结束函数

bool CMy2048Dlg::CalcEnd(void)
&#123;
    if (wop)
    &#123;
        //首先处理横轴:
        for (int i = 0; i < Count; i++)
        &#123;
            for (int j = 0; j < Count; j++)
            &#123;
                if (m_nArray[i][j] == 0)
                &#123;
                    return false;
                &#125;
                if (j + 1 == Count)
                &#123;
                    break;
                &#125;
                if (m_nArray[i][j] == m_nArray[i][j + 1])//判断是否可以累加
                &#123;
                    return false;
                &#125;
            &#125;
        &#125;
        //处理纵轴
        for (int i = 0; i < Count; i++)
        &#123;
            for (int j = 0; j < Count; j++)
            &#123;
                if (m_nArray[i][j] == 0)
                &#123;
                    return false;
                &#125;
                if (i + 1 == Count)
                &#123;
                    break;
                &#125;
                if (m_nArray[i][j] == m_nArray[i + 1][j])
                &#123;
                    return false;
                &#125;
            &#125;
        &#125;
        return true;
    &#125;return false;
&#125;

6.累加函数

void CMy2048Dlg::Add( deque<int> &list)
&#123;
    if (wop)
    &#123;
        for (int i = 0; i <int(list.size()); i++)
        &#123;
            if (list[i] == 0)
                continue;
            for (int j = i + 1; j <int(list.size()); j++)
            &#123;
                if (list[i] == list[j])
                &#123;
                    list[i] *= 2;
                    list[j] = 0;
                    break;
                &#125;
//如果当前的值不为0  跳出内循环,没必要再比较例如:  4 2 2 ; 当 list[0]=4,list[1]=2list[1] = 2 != 0,直接跳出循环,没必要再比较 list[2]与 list[0]
                if (list[j] != 0)
                &#123;
                    break;
                &#125;
            &#125;
        &#125;
        //重新排列顺序,不足补0;
        //例如 4 2  经过上面的代码其实没有任何变化累加,但是累加最后的结果要变为  4 2 0 0  
        deque<int> tempLst;
        for (int i = 0; i <int(list.size()); i++)
        &#123;
            //双端队列支持对元素的下标访问
            if (list[i] != 0)
            &#123;
                tempLst.push_back(list[i]);
            &#125;
        &#125;
        list = tempLst; //这个时候 list的元素为: 4 2 ,所以下面要补0
        for (int i = list.size(); i < Count; i++)
        &#123;
            list.push_back(0); //list 的元素为: 4 2 0 0 
        &#125;
    &#125;
&#125;

7.向上按钮响应函数

void CMy2048Dlg::OnBnClickedButton2()
&#123;
    // TODO: 在此添加控件通知处理程序代码
    //sign = 1;
    CString str;
    bool bRet;
    if (wop)
    &#123;
        List1.AddString(_T("↑"));
        CString strr;
        strr = TravelArrey();
        WriteTXT(strr);
        bRet = Up();
        TOPControl(bRet);
    &#125;
&#125;

8.TOPControl函数

void CMy2048Dlg::TOPControl(bool n)
&#123;
    if (CalcEnd())//判断游戏是否结束
    &#123;
    AfxMessageBox(_T("GameOver!"));List1.AddString(_T("GameOver!"));
                //List1.AddString(_T("GameOver!"));
        int buff[4][4];
        int max = 0;
        for (int i = 0; i < 4; i++)//遍历找出最大值并输出
            for (int j = 0; j < 4; j++)
            &#123;
                buff[i][j] = m_nArray[i][j];
                if (buff[i][j] > max)
                    max = buff[i][j];
            &#125;
        CString st;
        st.Format(_T("m_%d\n"), max);
        WriteNameTXT(st);//记录游戏信息
        CString strrr;
        strrr.Format(_T("O_%s\n"), Userr.name);
        WriteTXT(strrr);
        Reset();//重置游戏
        TOPList();//排行榜函数
    &#125;
    else
    &#123;
        if (n)
        &#123;
            RandonNum();
            Invalidate(TRUE);
            if (CalcEnd())
            &#123;                AfxMessageBox(_T("GameOver!"));List1.AddString(_T("GameOver!"));
                int buff[4][4];
                int max = 0;
                for (int i = 0; i < 4; i++)//遍历找出最大值并输出
                    for (int j = 0; j < 4; j++)
                    &#123;
                        buff[i][j] = m_nArray[i][j];
                        if (buff[i][j] > max)
                            max = buff[i][j];
                    &#125;
                CString st;
                st.Format(_T("m_%d\n"), max);
                WriteNameTXT(st);
                CString strrr;
                strrr.Format(_T("O_%s\n"), Userr.name);
                WriteTXT(strrr);
                Reset();
                TOPList();
            &#125;
        &#125;
    &#125;
    Invalidate(TRUE);
&#125;

9.定时器相关函数

void CMy2048Dlg::OnTimer(UINT_PTR nIDEvent)
&#123;
    if(nIDEvent==1&&wop)//判断事件来自哪个定时器
    &#123;
        // TODO: 在此添加消息处理程序代码和/或调用默认值
        //sign2 = 0;
        CString str, str1, str2, str3;
        int Minute, Second; //分,秒
        Minute = ct / 60; //分
        Second = ct % 60;  //秒
        if (Second == 0)
        &#123;
            Second = 59;
            if (Minute > 0)
                Minute = Minute - 1;
        &#125;
        else
        &#123;
            Second = Second - 1;//自减1倒计时
        &#125;
        if (Second >= 10)
            str2.Format(_T("%d:%d"), Minute, Second);
        else
            str2.Format(_T("%d:0%d"), Minute, Second);
        //str2.Format(_T("%d"), Second);
        SetDlgItemText(IDC_EDIT2, str2);
        if (Minute == 0 && Second == 0&&sign2==0)
        &#123;
            sign2++;
            //AfxMessageBox(_T("GameOver!"));
            if (MessageBox(_T("Game Over!"), _T("时间到"))== 1)
            &#123;
                sign2 = 0;
                List1.AddString(_T("GameOver!"));
                
                int buff[4][4];
                int max = 0;
                for (int i = 0; i < 4; i++)//遍历找出最大值并输出
                    for (int j = 0; j < 4; j++)
                    &#123;
                        buff[i][j] = m_nArray[i][j];
                        if (buff[i][j] > max)
                            max = buff[i][j];
                    &#125;
                CString st;
                st.Format(_T("m_%d\n"), max);
                WriteNameTXT(st);
                Invalidate(TRUE);
                CString strrr;
                strrr.Format(_T("O_%s\n"), Userr.name);
                WriteTXT(strrr);
                Reset();//此处修改只显示一次
                
                TOPList();
            &#125;        
        &#125;
        else if (Minute == 0 && Second == 0 && sign2 != 0)
        &#123;
            sign2++;
            ct = COUNT;
        &#125;
        ct = ct - 1;

        CTime tm = CTime::GetCurrentTime();
        str3.Format(_T("%d-%02d-%02d  %02d:%02d:%02d"), tm.GetYear(), tm.GetMonth(), tm.GetDay(), tm.GetHour(), tm.GetMinute(), tm.GetSecond());
        GetDlgItem(IDC_EDIT1)->EnableWindow(FALSE);
        GetDlgItem(IDC_EDIT1)->SetWindowText(str3);
    &#125;
    else if (nIDEvent == 2)
    &#123;
        CString str;
        if (sign == 10) sign = 1;
        else sign++;
        switch (sign)//选择要显示的名人名言
        &#123;
        case 1:
            str = word1;
            SetDlgItemText(IDC_EDIT3, str);
            break;
        case 2:
            str = word2;
            SetDlgItemText(IDC_EDIT3, str);
            break;
        case 3:
            str = word3;
            SetDlgItemText(IDC_EDIT3, str);
            break;
        case 4:
            str = word4;
            SetDlgItemText(IDC_EDIT3, str);
            break;
        case 5:
            str = word5;
            SetDlgItemText(IDC_EDIT3, str);
            break;
        case 6:
            str = word6;
            SetDlgItemText(IDC_EDIT3, str);
            break;
        case 7:
            str = word7;
            SetDlgItemText(IDC_EDIT3, str);
            break;
        case 8:
            str = word8;
            SetDlgItemText(IDC_EDIT3, str);
            break;
        case 9:
            str = word9;
            SetDlgItemText(IDC_EDIT3, str);
            break;
        case 10:
            str = word10;
            SetDlgItemText(IDC_EDIT3, str);
            break;
        &#125;
    &#125;
    CDialogEx::OnTimer(nIDEvent);
&#125;

10.排行榜函数

void CMy2048Dlg::TOPList()
&#123;
    CString cstrFileFullPath = _T("C:\\Users\\11817\\Desktop\\计算机大实验\\2048demo\\name.txt");
    USES_CONVERSION;
    CStdioFile cssFile;
    CString cstrLine;
    //usr *u = new usr;
    u.RemoveAll();
    int z=0;
    BOOL ret = cssFile.Open(cstrFileFullPath,
        CFile::modeRead | CFile::shareDenyNone);
    if (!ret)
    &#123;
        AfxMessageBox(_T("读取文件失败"));
        return;
    &#125;
    cssFile.SeekToBegin();
    while (cssFile.ReadString(cstrLine))
    &#123;
        
        //z++;
        if (cstrLine=="u_")
        &#123;
            continue;
        &#125;
        else if (cstrLine != "u_" && cstrLine.GetAt(0)=='u')
//查找用户名关键字
        &#123;
            usr temp;
            int l=cstrLine.GetLength();
            CString ste= cstrLine.Right(l-2);
            //ste.Format(_T("%s"),)
            temp.name = ste;
            temp.order = z+1;
            u.Add(temp);
            //u = new usr;
            //u[z].name = cstrLine;
            z++;
            //countt++;
        &#125;
        else if (cstrLine != "u_" &&cstrLine.GetAt(0) == 'm')//查找成绩关键字
        &#123;
            int i,k,l;
            char s[4] = &#123;0&#125;;
            l = cstrLine.GetLength();
            for (i = 0; i<l-2; i++)
            &#123;
                char y;
                 y= cstrLine.GetAt(i + 2);
                 s[i] = y;
            &#125;
            //s.Add( '\0');             
            k = atoi(s);
            u[z-1].MAX = k;    
        &#125;
    &#125;
    usr max;
    int tempmax = z - 1;//交换排序
    for (int i = 0; i <z; i++)
    &#123;
        for (int j = z-1; j >0; j--)
        &#123;
            if (u[i].MAX <= u[j].MAX)
            &#123;
                max = u[i];
                u[i] = u[j];
                u[j] = max;
            &#125;
        &#125;
    &#125;
    List2.ResetContent();
    TOPu.RemoveAll();//清空排序记录
    for (int i=0,v=0; i<z-1&&v<20;i++ )
    &#123;
        CString str,str2;
        str2.Format(_T("|分数:"));
        if (u[i].MAX != 0)
        &#123;
            usr temp;
            if (v < 15)
            &#123;
                str.Format(_T("第%d名:%-8s%s%-4d"), v + 1, u[i].name, str2, u[i].MAX);
                List2.AddString(str);//输出至列表
            &#125;
            temp = u[i];
            TOPu.Add(temp);
            v++;
        &#125;
    &#125;
&#125;

11.回放函数

void CMy2048Dlg::watch(int x,int s)
&#123;
    //TOPu[x];
    CPaintDC dc(this);
    int y=0;
    CString cstrFileFullPath = _T("C:\\Users\\11817\\Desktop\\计算机大实验\\2048demo\\data.txt");
    USES_CONVERSION;
    CStdioFile cssFile;
    CString cstrLine;
    BOOL ret = cssFile.Open(cstrFileFullPath,
        CFile::modeRead | CFile::shareDenyNone);
    if (!ret)
    &#123;
        AfxMessageBox(_T("读取文件失败"));
        return;
    &#125;
    cssFile.SeekToBegin();
    while (cssFile.ReadString(cstrLine))
    &#123;
        int u=0;
        if (cstrLine.GetAt(0) == 'L')
            y++;
        if (y == TOPu[x].order)
        &#123;
            u = 1;
            /*CString stt;
            stt.Format(_T("%s"), TOPu[x].name);
            SetDlgItemText(IDC_EDIT4, stt);*/
            for (int i = 0;  ; i++)
            &#123;
                if (cssFile.ReadString(cstrLine) && cstrLine.GetAt(0) != 'O'&&cstrLine.GetAt(0) != 'L')
                &#123;
                    for (int j = 0; j < Count; j++)
                        for (int h = 0; h < Count; h++)
                        &#123;
                            CString temp; char *temps;
                            temp = cstrLine.Mid(25 * j + 5 * h, 25 * j + 5 * (h + 1));
                            temps = W2A(temp.GetBuffer());
                            int m=atoi(temps);
                            n_nArray[j][h] = m;
                        &#125;
                    Invalidate();
                    XSleep(s);//延时300ms
                    //List1.AddString(_T("*"));
                &#125;
                else
                    break;
            &#125;
        &#125;
        if(u)
            break;
    &#125;
    wop = TRUE;
&#125;

文章作者: Qianyu Zhang
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Qianyu Zhang !
  目录