基于MFC实现的赛车游戏

一、问题描述

游戏背景为一环形车道图,选择菜单选项“开始游戏”则可开始游戏。游戏的任务是使用键盘上的方向键操纵赛道上的蓝色赛车追赶红色赛车,红色赛车沿车道顺时针行驶,出发点和终点均位于车道左上方。任一赛车先达到终点则比赛结束。

二、编程要求

  • 矩形车道和赛车的图像可辨认,显示正确
  • 赛道内有红色和蓝色两辆赛车,红色赛车由程序控制,蓝色赛车用键盘操纵
  • 赛车在矩形车道上运行,方向应与赛车形状相匹配
  • 用光标键控制蓝色赛车追赶红色赛车,赛车不能偏离跑道
  • 当某一赛车到达终点时,显示消息框
  • 正确设置游戏菜单(开始,结束)

三、要点分析

本题主要涉及到的知识点有:定时器消息、位图显示、画笔/画刷的使用、显示文字等工作,难度适中。

该题的难点在于如何保证赛车的头部永远向前。这里使用了一幅位图,它由四部分组成,如图1所示。为了方便编程,假定赛车是正方形,即赛车位图的宽度和高度相同。在本题中每一辆赛车位图的宽度和高度均为48个像素点,整个位图的宽度为192个像素点,高度为48个像素点。根据赛车在运行时的方向,将赛车位图的一部分显示到屏幕。

四、解题步骤

首先用AppWizard生成一个名为Car的SDI程序框架,其选项均用缺省设置。

编辑项目的菜单资源,在框架窗口的主菜单(IDR_MAINFRAME)中添加一个下拉菜单选项“游戏”,添加两个菜单选项“开始”和“结束”,并删除不必要的菜单选项,如图2所示。菜单属性设置如表5所示。

IDCaptionPrompt
ID-BEGIN开始开始
ID_STOP结束结束

利用ClassWizrd为视图类添加与这些菜单选项对应的成员函数。进入ClassWizard的Message Maps选项卡,选择Class Name项为CCarView,在Object IDs列表框中分别选择新添加的菜单选项的ID,在Messages列表框中选择COMMAND,按下Add Function按钮添加成员函数。ClassWizard会为这些菜单选项添加相应的消息响应函数(目前尚没有具体内容,需要程序员自行加入有关的处理代码),并将其声明加入OCarView类定义,在消息映射宏中加入相应的消息映射。

使用Developer Studio菜单的Insert / Resource…选项调出Insert Source对话框,为项目添加两个位图资源,分别表示红车和蓝车的位图。相应位图的资源ID分别为IDB_BITMAP1和IDB_BITMAP2。

完成以上工作后,即可修改程序框架,添加必要的代码。

五、源程序清单

在视图类OCarView类头文件首部添加三个常量,在类中再添加若干数据成员:

const CRect rectRed = CRect (30, 30, 750, 490);      //红车位置
const CRect rectBlue = CRect (30, 90, 700, 430);     //蓝车位置
const CRect rectGreen = Crect (150, 150, 640, 340);  //草坪位置
class OCarView: public CView
{//此处略去若干行由系统生成的代码CBitmap m_bmpRed;                //红车的位图CBitmap m_bmpBlue;               //蓝车的位图int m_nWidth;                    //位图的宽度int m_nHeight;                   //位图的高度CRect m_rectRed;                 //红车的区域int m_nRed;                      //红车的方向,0:左;1:下;2:右;3:上CRect m_rectBlue;                //蓝车的区域int m_nBlue;                     //蓝车的方向,0:左;1:下;2:右;3:上
};

在视图类的构造函数中添加代码:

CCarView ::CCarView ( )
{m_bmpRed. LoadBitmap (IDB_BITMAP1);m_bmpBlue. LoadBitmap (IDB_BITMAP2);BITMAP BM;m_bmpRed. GetBitmap (&BM);m_nWidth = BM. bmWidth/4;m_nHeight = BM. bmHeight;
}

在视图类的虚函数OnInitialUpdate ( )中添加代码:

void CCarView :: OnInitialUpdate ( )
{CView :: OnInitialUpdate ( );//定义红车的赛道m_rectRed = CRect (rectRed. Left, rectRed. top, rectRed. left + m_nWidth, rectRed. top + m_nHeight);       //定义蓝车的赛道m_rectBlue = CRect (rectBlue. left, rectBlue. top,
rectBlue. left + m_nWidth, rectBlue. top + m_nHeight);   //赛车开始时方向均向右m_nRed = m_nBlue = 0;                                
}

在OnDraw ( )函数中添加代码:

void CCarView :: OnDraw (CDC * pDC)
{CCarDoc * pDoc = GetDocument ( );ASSERT_VALID (pDoc);CBrush brushgreen, * pubrushOld;CPen penBlue, * ppenOld;penBlue. CreatePen (PS_SOLID, 1, RGB (0, 0, 128) );brushgreen. CreateSolidBrush (RGB (0, 255, 0) );ppenOld = pDC - > SelectObject (&penBlue);pbrushOld = pDC - > SelectObject (&brushgreen);pDC - > Rectangle (&rectRed);              //画赛道pDC - > SelectStockObject (WHITE_BRUSH);pDC - > Rectangle (&rectGreen)//画中间区域CDC MemDC;MemDC. CreateCompatibleDC (NULL);          //建立虚拟设备环境MemDC. SelectObject (&m_bmpRed);pDC - > BitBlt (m_rectRed. left + 1, m_rectRed. top + 1, m_nWidth, m_nHeight, &MemDC, m_nWidth * m_nRed, 0, SRCCOPY);     //画红车MemDC. SelectObject (&m_bmpBlue);pDC - > BitBlt (m_rectBlue. left + 1, m_rectBlue. top + 1, m_nWidth, m_nHeight, &MemDC, m_nWidth * m_rectBlue, 0, SRCCOPY);     //画蓝车pDC - > SelectObject (pbrushOld);pDC - > SelectObject (ppenOld);
}

在视图类中添加定时器消息处理函数OnTimer ( ),并在其中添加代码:

void CCarView :: OnTimer (UINT nIDEvent)
{InvalidateRect (m_rectRed);switch (m_nRed)                           //红车的方向{case 0:                                    //向右if (m_rectRed. right + 10 < rectRed. right)m_rectRed + = CSize (10, 0);elsem_nRed = 1;break;case 1:                          //向下if (m_rectRed. bottom + 10 < rectRed. bottom)m_rectRed + = CSize (0, 10);elsem_nRed = 2break;case 2:                          //向左if (m_rectRed. left > rectRed. left)m_rectRed + = CSize (-10, 0);elsem_nRed = 3;break;case 3:                        //向上if (m_rectRed. top > rectRed. top)m_rectRed + = CSize (0, -10);else{KillTimer (1);                   //游戏结束MessageBox (〃You Lose.);}}InvalidateRect (m_rectRed);CView :: OnTimer (nIDEvent);
}

在视图类中添加键盘按下消息处理函数OnKeyDown ( ),并在其中添加代码:

void CCarView :: OnKeyDown (UINT nchar, UINT nRepCnt, UINT nFlags)
{InvalidateRect (m_rectBlue);switch (nChar){case 39:                      //向左光标键m_nBlue = 0;if (m_rectBlue. right + 10 < rectBlue. right&&m_rectBlue. bottom < rectGreen. top)m_rectBlue + = CSize (10, 0);break;case 40:                   //向下光标键m_nBlue = 1;if (m_rectBlue. bottom + 10 < rectBlue. bottom&&m_rectBlue. left > rectGreen. right)m_rectBlue + = CSize (0, 10);break;case 37:                  //向右光标键m_nBlue = 2;if (m_rectBlue.left > rectBlue. left&&m_rectBlue. top > rectGreen. bottom)m_rectBlue + = CSize (-10, 0);break;case 38:                      //向上光标键m_nBlue = 3;if (m_rectBlue. top > rectRed. top&&m_rectBlue. right < rectGreen. left)m_rectBlue + = CSize (0, -10);if (m_rectBlue. Bottom< rectBlue. top){KillTimer (1);         / /游戏结束MessageBox (〃You Win.);}}InvalidateRect (m_rectBlue);CView :: OnKeyDown (nChar, nRepCnt, nFlags);
}

在视图类中新增菜单对应的消息处理函数中添加代码:

void CCarView :: OnBegin ( )
{OnInitialUpdate ( );SetTimer (1, 100, NULL);                  / /设置定时器
}
void CCarView :: OnStop ( )
{KillTimer (1);                           / /删除定时器
}

六、输入输出

用户可选择框架窗口菜单“演示”中的选项“开始”,运行结果如图3所示。

七、小结

在视图类中重载了键盘按下消息处理函数OnKeyDown ( ),在该函数中,仅响应用户按下的四个方向键,用以修改赛车的位置。

在OnKeyDown ( )中调用了两次InvalidateRect ( ),两者都只有一个参数,表明擦除时应重画背景。

八、进一步工作

本程序还可以添加“信号灯”功能,在中间白色区域画一信号灯,当用户选择了“开始”后不能马上比赛,而要等到信号灯从红变黄,再从黄变绿后,才能开始比赛。

另外还可以添加难度菜单,难度越高,红车速度越快。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/59709.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RHCE的学习(12)

第九章 Ubuntu 什么是Ubuntu 概述 Ubuntu&#xff08;乌班图&#xff09;属于Debian系列&#xff0c;Debian是社区类Linux的典范&#xff0c;是迄今为止最遵循GNU规范的Linux系统。 Debian最早由Ian Murdock于1993年创建&#xff0c;分为三个版本分支&#xff08;branch&…

【案例】故障雪花屏

开发平台&#xff1a;Unity 6.0 开发工具&#xff1a;Shader Graph 参考视频&#xff1a;【U2D Shader Graph】❄️雪❄️花❄️屏❄️   一、效果图 二、Shader Graph 路线图 三、案例分析 核心思路&#xff1a;雪花屏幕效果 &#xff08;混合&#xff09; 原图像 最终图像…

有什么办法换网络ip动态

在数字化时代&#xff0c;网络已成为我们生活、工作不可或缺的一部分。然而&#xff0c;随着网络应用的日益广泛&#xff0c;IP地址作为设备在网络中的唯一标识&#xff0c;其重要性不言而喻。动态换IP&#xff0c;作为一种灵活且高效的网络技术&#xff0c;正逐渐受到越来越多…

Spring Boot中集成MyBatis操作数据库详细教程

目录 前言1. 项目依赖配置1.1 引入MyBatis和数据库驱动依赖1.2 数据源配置 2. 创建数据库映射实体类3. 创建Mapper层接口4. 创建Service层4.1 定义Service接口4.2 实现Service接口 5. 创建Controller层6. 运行和测试项目6.1 启动项目6.2 测试接口 7. 总结 前言 在Java开发中&a…

【大语言模型】ACL2024论文-07 BitDistiller: 释放亚4比特大型语言模型的潜力通过自蒸馏

【大语言模型】ACL2024论文-07 BitDistiller: 释放亚4比特大型语言模型的潜力通过自蒸馏 目录 文章目录 【大语言模型】ACL2024论文-07 BitDistiller: 释放亚4比特大型语言模型的潜力通过自蒸馏目录摘要研究背景问题与挑战如何解决创新点算法模型实验效果代码推荐阅读指数&…

鸿蒙next打包流程

目录 下载团结引擎 添加开源鸿蒙打包支持 打包报错 路径问题 安装DevEcoStudio 可以在DevEcoStudio进行打包hap和app 包结构 没法直接用previewer运行 真机运行和测试需要配置签名,DevEcoStudio可以自动配置, 模拟器安装hap提示报错 安装成功,但无法打开 团结1.3版本新增工具…

基于Jeecgboot3.6.3vue3的flowable流程online表单的审批使用介绍

更多技术支持与服务请加入我的知识星球或加我微信&#xff0c;名称:亿事达nbcio技术交流社区https://t.zsxq.com/iPi8F 今天介绍一下基于jeecgboot3.6.3的flowable流程使用online表单进行审批的情况 1、首先建立一个online应用类型的流程&#xff0c;如下&#xff1a; 2、进行…

【LeetCode】【算法】238. 除自身以外数组的乘积

LeetCode 238. 除自身以外数组的乘积 题目描述 给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据保证数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位整数范围内。 请不…

如何构建一个可扩展的测试自动化框架?

以下为作者观点&#xff1a; 假设你是测试自动化方面的新手&#xff0c;想参与构建一个框架。在这种情况下&#xff0c;重要的是要了解框架所需的组件&#xff0c;以及它们是如何组合的。思考项目的具体需求和目标&#xff0c;以及可能遇到的困难和挑战。 假如你是一个测试架…

实战:索引的命中机制

在 SQL Server 中,查询是否能命中索引(即是否能使用 Index Seek)取决于多个因素,包括索引的结构、查询条件的排列、和数据库优化器的策略。以下是一些常见的命中索引和不能命中索引的情况,及其详细解释: 一、命中索引的情况 1. 前导列匹配(典型的命中索引场景) 索引结…

使用Docker快速部署FastAPI Web应用

Docker是基于 Linux 内核的cgroup、namespace以及 AUFS 类的Union FS 等技术&#xff0c;对进程进行封装隔离&#xff0c;一种操作系统层面的虚拟化技术。Docker中每个容器都基于镜像Image运行&#xff0c;镜像是容器的只读模板&#xff0c;容器是模板的一个实例。镜像是分层结…

C++【string类,模拟实现string类】

&#x1f31f;个人主页&#xff1a;落叶 &#x1f31f;当前专栏: C专栏 目录 为什么学习string类 C语言中的字符串 标准库中的string类 auto和范围for auto关键字 迭代器 范围for string类的常用接口说明和使用 1. string类对象的常见构造 2.string类对象的容量操作 3…

A019基于SpringBoot的校园闲置物品交易系统

&#x1f64a;作者简介&#xff1a;在校研究生&#xff0c;拥有计算机专业的研究生开发团队&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取&#xff0c;记得注明来意哦~&#x1f339; 赠送计算机毕业设计600…

【赵渝强老师】Redis的RDB数据持久化

Redis 是内存数据库&#xff0c;如果不将内存中的数据库状态保存到磁盘&#xff0c;那么一旦服务器进程退出会造成服务器中的数据库状态也会消失。所以 Redis 提供了数据持久化功能。Redis支持两种方式的持久化&#xff0c;一种是RDB方式&#xff1b;另一种是AOF&#xff08;ap…

Excel:vba实现批量插入图片批注

实现的效果&#xff1a;实现的代码如下&#xff1a; Sub InsertImageNamesAndPictures()Dim PicPath As StringDim PicName As StringDim PicFullPath As StringDim RowNum As IntegerDim Name As StringDim Comment As CommentDim folder As FileDialog 定义文件选择对话框 清…

tomcat启动失败和缓存清理办法

tomcat只在学校接触过并且是在window xp和win7的电脑上配置过&#xff08;中途升级过电脑系统&#xff09;&#xff0c;只记得在windows系统上可以将其设置成服务管理。但我已毕业10多年了&#xff0c;学的知识早就不知道丢哪里了。这次为了修改一个07&#xff0c;08年的项目&a…

ReactPress:深入解析技术方案设计与源码

ReactPress Github项目地址&#xff1a;https://github.com/fecommunity/reactpress 欢迎提出宝贵的建议&#xff0c;欢迎一起共建&#xff0c;感谢Star。 ReactPress是一个基于React框架开发的开源发布平台&#xff0c;它不仅仅是一个简单的博客系统&#xff0c;更是一个功能全…

A20红色革命文物征集管理系统

&#x1f64a;作者简介&#xff1a;在校研究生&#xff0c;拥有计算机专业的研究生开发团队&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取&#xff0c;记得注明来意哦~&#x1f339; 赠送计算机毕业设计600…

先锋精科委身芯片“圈子” 引致交易不公允和信披不透明

不要违背圈子的规则&#xff0c;但也不要盲从圈子的规则。 ——语出马云。 引 言 “圈子”是钥匙&#xff0c;也是一把锁。 走进“圈子”&#xff0c;将获得包括资金、订单、货源、技术等企业发展所需的资源&#xff0c;能够助推一家企业乃至整个行业的跨越式发展&#…

MinerU容器构建教程

一、介绍 MinerU作为一款智能数据提取工具&#xff0c;其核心功能之一是处理PDF文档和网页内容&#xff0c;将其中的文本、图像、表格、公式等信息提取出来&#xff0c;并转换为易于阅读和编辑的格式&#xff08;如Markdown&#xff09;。在这个过程中&#xff0c;MinerU需要利…