基于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; 原图像 最终图像…

图像手动标注-labelme+yolo格式导出

conda环境 运行以下命令来激活你的虚拟环境&#xff1a; conda activate labelme如果你没有创建 labelme 环境&#xff0c;首先需要创建一个环境并安装 labelme&#xff1a; conda create -n labelme python3.8 conda activate labelme conda install -c conda-forge labelm…

有什么办法换网络ip动态

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

unity实习生面试

北京教育中厂的成都分部 11.5 时长有28分钟 一面二面合并了 面试官人挺好的&#xff0c;也不是特别急&#xff0c;答的不是很好的问题面试官直接跳过了 顺序不是很统一 只写记得的部分 1.问了值类型和引用类型的区别 2. 问了ugui的组件有哪些 ugui有哪些优化方案 答用打图集…

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…

OpenCV相机标定与3D重建(2)鱼眼相机模型

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 鱼眼相机是一种具有非常宽视野的相机&#xff0c;通常会产生强烈的径向畸变。鱼眼相机模型旨在捕捉这种畸变&#xff0c;以便能够准确地处理和校…

Matplotlib 绘图艺术:从新手到高手的全面指南

引言 在数据科学和机器学习领域&#xff0c;数据可视化是一项至关重要的技能。一个优秀的可视化图表可以直观地展示数据的内在规律&#xff0c;帮助我们更好地理解数据&#xff0c;并做出更明智的决策。而在众多的绘图库中&#xff0c;Matplotlib 是 Python 中最强大、最灵活的…

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

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

RocketMQ部署教程

拉取 RocketMQ 镜像&#xff1a; 首先&#xff0c;从 Docker Hub 获取最新的 RocketMQ 镜像&#xff1a; docker pull apache/rocketmq:latest创建 Docker 网络&#xff1a; 为了使各容器之间能够通信&#xff0c;创建一个名为 rocketmq 的网络&#xff1a; docker network cre…

ORACLE批量插入更新如何拆分大事务?

拆分大事务 一、批量插入更新二、拆分事务之前文章MYSQL批量插入更新如何拆分大事务?说明了Mysql如何拆分,本篇文章探讨Oracle或OceanBase批量插入更新拆分大事务的问题 一、批量插入更新 oracle批量插入更新可使用merge语法eg: merge test ausing test_tmp bon (a.id = b.id…

鸿蒙next打包流程

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

chatgpt3.5权重参数有多少MB;llama7B权重参数有多少MB

目录 chatgpt3.5权重参数有多少MB llama7B权重参数有多少MB chatgpt3.5权重参数有多少MB 关于ChatGPT 3.5的权重参数占用的存储空间大小,虽然直接给出具体的MB数值可能较为困难(因为这取决于多种因素,如参数表示的精度、是否进行了压缩等),但可以根据其参数量来估算一个…

基于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…

android——jetpack startup初始化框架

一、jetpack startup Android Jetpack Startup是一个库&#xff0c;它简化了Android应用启动过程&#xff0c;尤其是对于那些需要处理复杂数据绑定和初始化逻辑的应用。它的核心在于提供了一个StartupComponent&#xff0c;用于声明应用的初始化逻辑&#xff0c;这个逻辑会在首…