博客
关于我
逃逸的小球(BALL Escape)
阅读量:644 次
发布时间:2019-03-14

本文共 2983 字,大约阅读时间需要 9 分钟。

由于最近要找工作,为了熟悉编程环境,怀着学习MFC的热情,编写了这个小程序。本文主要探讨了MFC环境下的绘图和按键控制,过程中遇到了一些技术难点,其中第四节的关键技术攻克尤为重要,希望能得到各位大神的指导。


功能介绍

本应用程序主要包含一个红球和30个蓝球,用户通过按下F2键开始游戏,利用方向键控制红球的移动方向,避免与蓝球碰撞。游戏背景采用经典的魂斗罗音乐,用户需要记录红球的逃逸时间,测试应变能力。程序界面较为简陋,但功能基本完成。


采用MFC技术

2.1 控件背景重绘

在MFC中,如果将对话框的背景设置为白色,需要手动重绘对话框。为此,可以创建一个白色画刷,并在对话框的CtlColor事件中返回该画刷,实现对话框背景的重绘。

#define WRITE RGB(255, 255, 255)HBRUSH CEscapeBallDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) {    HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);    if (nCtlColor == CTLCOLOR_DLG)        return m_Brush;    return hbr;}

2.2 按键响应

为了避免按回车键时关闭窗口,我们采用了PreTranslateMessage消息预处理函数,隐藏了默认的按键处理逻辑,实现了按F2键开始游戏的功能。

BOOL CEscapeBallDlg::PreTranslateMessage(MSG* pMsg) {    if (pMsg->wParam == VK_RETURN)        return TRUE;    if (pMsg->wParam == VK_F2 && !m_bEscaping) {        BeginGame();        return CDialog::PreTranslateMessage(pMsg);    }    return CDialog::PreTranslateMessage(pMsg);}

2.3 播放音乐

为了提升游戏氛围,我们采用了MFC的PlaySound函数,将WAV格式的音乐文件作为资源嵌入到项目中,实现了背景音乐的循环播放。

PlaySound(MAKEINTRESOURCE(IDR_WAVE_HUNDOULUO), NULL, SND_RESOURCE | SND_ASYNC | SND_LOOP);

球移动碰撞算法

程序中采用了简单的碰撞算法来控制球的运动方向。蓝球的运动方向主要有两种情况:一是按随机方向运动,二是根据红球的位置作为运动方向。具体实现如下:

void CEscapeBallDlg::ComputeForward(BallInfo* bBall, BallInfo* rBall, BOOL is_rand) {    int x = rBall->pos_x, y = rBall->pos_y;    int x1 = bBall->pos_x, y1 = bBall->pos_y;    if (is_rand) {        x1 = rand() % m_MaxX;        y1 = rand() % m_MaxY;    }    offset_x = fabs((x - x1)) / sqrt(pow((x - x1), 2) + pow((y - y1), 2)) * MOVEOFFSET;    offset_y = fabs((y - y1)) / sqrt(pow((x - x1), 2) + pow((y - y1), 2)) * MOVEOFFSET;    bBall->offset_x = (x1 - x) < 0 ? -offset_x : offset_x;    bBall->offset_y = (y1 - y) < 0 ? -offset_y : offset_y;}

关键技术攻克

4.1 问题研究

在控制方向键时,我们发现按键按下后会有短暂的延迟,尤其是在长时间按键时会影响用户体验。通过分析,我们发现这是由于操作系统底层对按键状态的判断时间引起的。

4.2 解决方法

经过多次尝试,我们发现线程化处理按键状态可以有效解决这个问题。具体实现如下:

UINT CEscapeBallDlg::RedBallMoveFunc(LPVOID lParam) {    CEscapeBallDlg* pDlg = (CEscapeBallDlg*)lParam;    while (pDlg->m_bEscaping) {        BYTE keyState = 0;        keyState |= (GetKeyState(VK_UP) & 0x8000) ? 0x08 : 0;        keyState |= (GetKeyState(VK_DOWN) & 0x8000) ? 0x04 : 0;        keyState |= (GetKeyState(VK_LEFT) & 0x8000) ? 0x02 : 0;        keyState |= (GetKeyState(VK_RIGHT) & 0x8000) ? 0x01 : 0;        if ((keyState & 0x01) && (keyState & 0x02))            keyState &= 0x0C;        if ((keyState & 0x04) && (keyState & 0x08))            keyState &= 0x03;        switch (keyState) {            case UP: offset_x = 0, offset_y = -MOVEOFFSET; break;            case DOWN: offset_x = 0, offset_y = MOVEOFFSET; break;            case LEFT: offset_x = -MOVEOFFSET, offset_y = 0; break;            case RIGHT: offset_x = MOVEOFFSET, offset_y = 0; break;            // 其他方向类似        }        if (offset_x || offset_y) {            pDlg->ReDrawRedBall(offset_x, offset_y);            if (!pDlg->CheckEscape())                pDlg->EndGame();        }        Sleep(30);    }    return 0;}

通过线程化处理按键状态,有效解决了按键延迟问题,提升了用户操作体验。

转载地址:http://iygoz.baihongyu.com/

你可能感兴趣的文章
No module named ‘MySQLdb‘错误解决No module named ‘MySQLdb‘错误解决
查看>>
No new migrations found. Your system is up-to-date.
查看>>
No qualifying bean of type XXX found for dependency XXX.
查看>>
No resource identifier found for attribute 'srcCompat' in package的解决办法
查看>>
no session found for current thread
查看>>
No toolchains found in the NDK toolchains folder for ABI with prefix: mips64el-linux-android
查看>>
NO.23 ZenTaoPHP目录结构
查看>>
no1
查看>>
NO32 网络层次及OSI7层模型--TCP三次握手四次断开--子网划分
查看>>
NoClassDefFoundError: org/springframework/boot/context/properties/ConfigurationBeanFactoryMetadata
查看>>
Node JS: < 一> 初识Node JS
查看>>
Node Sass does not yet support your current environment: Windows 64-bit with Unsupported runtime(72)
查看>>
Node-RED中使用JSON数据建立web网站
查看>>
Node-RED中使用json节点解析JSON数据
查看>>
Node-RED中使用node-random节点来实现随机数在折线图中显示
查看>>
Node-RED中使用node-red-browser-utils节点实现选择Windows操作系统中的文件并实现图片预览
查看>>
Node-RED中使用node-red-contrib-image-output节点实现图片预览
查看>>
Node-RED中使用node-red-node-ui-iframe节点实现内嵌iframe访问其他网站的效果
查看>>
Node-RED中使用Notification元件显示警告讯息框(温度过高提示)
查看>>
Node-RED中实现HTML表单提交和获取提交的内容
查看>>