基于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);
        else
            m_nRed = 1;
        break;
    case 1:                          //向下
        if (m_rectRed. bottom + 10 < rectRed. bottom)
            m_rectRed + = CSize (0, 10);
        else
            m_nRed = 2break;
    case 2:                          //向左
        if (m_rectRed. left > rectRed. left)
            m_rectRed + = CSize (-10, 0);
        else
            m_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 ( ),两者都只有一个参数,表明擦除时应重画背景。

八、进一步工作

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot赋能的共享汽车业务管理系统

4系统概要设计 4.1概述 本系统采用B/S结构(Browser/Server,浏览器/服务器结构)和基于Web服务两种模式&#xff0c;是一个适用于Internet环境下的模型结构。只要用户能连上Internet,便可以在任何时间、任何地点使用。系统工作原理图如图4-1所示&#xff1a; 图4-1系统工作原理…

「QT」几何数据类 之 QLineF 浮点型直线类

✨博客主页何曾参静谧的博客&#x1f4cc;文章专栏「QT」QT5程序设计&#x1f4da;全部专栏「VS」Visual Studio「C/C」C/C程序设计「UG/NX」BlockUI集合「Win」Windows程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「PK」Parasolid…

Elasticsearch专栏-4.es基本用法-查询api

es基本用法-查询api 说明查询所有某一字段匹配查询多字段查询bool查询范围查询精确查询正则匹配模糊查询结果处理 说明 es对数据的检索&#xff0c;总结下来就是两部分&#xff0c;即查询和处理。查询指的是查找符合条件的数据&#xff0c;包括查询所有、匹配查询、布尔查询、…

讨论一个mysql事务问题

最近在阅读一篇关于隔离级别的文章&#xff0c;文章中提到了一种场景&#xff0c;我们下面来分析一下。 文章目录 1、实验环境2、两个实验的语句执行顺序3、关于start transaction和start transaction with consistent snapshot4、实验结果解释4.1、实验14.2、实验24.3、调整实…

【AIGC】腾讯云语音识别(ASR)服务在Spring Boot项目中的集成与实践

腾讯云语音识别&#xff08;ASR&#xff09;服务在Spring Boot项目中的集成与实践 引言 在现代软件开发中&#xff0c;语音识别技术的应用越来越广泛&#xff0c;从智能助手到自动客服系统&#xff0c;语音识别技术都在发挥着重要作用。腾讯云提供了强大的语音识别服务&#…

基于Spring Boot的工程认证计算机课程管理系统

1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及&#xff0c;互联网成为人们查找信息的重要场所&#xff0c;二十一世纪是信息的时代&#xff0c;所以信息的管理显得特别重要。因此&#xff0c;使用计算机来管理基于工程教育认证的计算机课程管理平台的相…

2024年度国际荐酒师(香港)协会花式马刀开香槟表演赛在穗举行

2024年度国际荐酒师&#xff08;香港&#xff09;协会花式马刀开香槟表演赛在穗举行 近日&#xff0c;一场别开生面的花式马刀开香槟表演赛在广州四季酒店盛大举行&#xff0c;此次活动由国际荐酒师&#xff08;香港&#xff09;协会精心指导&#xff0c;广东海上丝绸之路文化促…

mysql全量与增量备份

binlog日志&#xff1a; 从上一次全量备份到下一次全量备份直接产生的数据。 一、全备和增量备份介绍 1、全量备份&#xff1a; 备份所有数据库或只备份一个数据库&#xff0c;全量备份之后&#xff0c;全量备份之前的binlog日志就没用了&#xff0c;一般生产环境会保留3-7天…

Web前端开发--HTML语言

文章目录 前言1.介绍2.组成3.基本框架4.常见标签4.1双标签4.1.1.标题标签4.2.2段落标签4.1.3文本格式化标签4.1.4超链接标签4.1.5视频标签4.1.6 音频标签 4.2单标签4.2.1换行标签和水平线标签4.2.2 图像标签 5.表单控件结语 前言 生活中处处都有网站&#xff0c;无论你是学习爬…

存算一体化与边缘计算:重新定义智能计算的未来

随着数据量爆炸式增长和智能化应用的普及&#xff0c;计算与存储的高效整合逐渐成为科技行业关注的重点。数据存储和处理需求的快速增长推动了对计算架构的重新设计&#xff0c;“存算一体化”技术应运而生。同时&#xff0c;随着物联网、5G网络、人工智能&#xff08;AI&#…

Kubernetes-ArgoCD篇-03-部署

1、从 Git 存储库创建应用程序 包含留言簿应用程序的示例存储库可在 https://github.com/argoproj/argocd-example-apps.git 上找到&#xff0c;以演示 Argo CD 的工作原理。 1.1 argocd server port-forward 我们这里通过port-forward 访问 Argo CD&#xff1a; kubectl p…

6层板设计常用知识笔记

1. 6层板设计叠层方案 &#xff08;1&#xff09;叠层方案优选以下方式 &#xff08;2&#xff09;过孔做固定孔时 plated作为固定孔时需要去掉勾选&#xff0c;焊盘去金属化。 &#xff08;3&#xff09;屏蔽罩&#xff1a;电源、主控存储、wifi需要加屏蔽罩&#xff0c;屏蔽…

【mongodb】数据库的安装及连接初始化简明手册

NoSQL(NoSQL Not Only SQL )&#xff0c;意即"不仅仅是SQL"。 在现代的计算系统上每天网络上都会产生庞大的数据量。这些数据有很大一部分是由关系数据库管理系统&#xff08;RDBMS&#xff09;来处理。 通过应用实践证明&#xff0c;关系模型是非常适合于客户服务器…

Unity跨平台基本原理

目录 前言 ​编辑 Mono Unity和Mono的关系 Unity跨平台必备概念 Mono利用 Mono主要构成部分 基于Mono跨平台的优缺点 IL2CPP Mono和IL2CPP的区别 Mono IL2CPP Mono和IL2CPP的使用建议 安装IL2CPP IL2CPP打包存在的问题 类型裁剪 泛型问题 前言 Unity跨平台的基…

【go从零单排】接口(interface)和多态(Polymorphism)

&#x1f308;Don’t worry , just coding! 内耗与overthinking只会削弱你的精力&#xff0c;虚度你的光阴&#xff0c;每天迈出一小步&#xff0c;回头时发现已经走了很远。 &#x1f4d7;概念 在Go语言中&#xff0c;interface 是一种重要的类型&#xff0c;用于定义一组方法…

Science Robotics 综述揭示演化研究新范式,从机器人复活远古生物!

在地球46亿年的漫长历史长河中&#xff0c;生命的演化过程充满着未解之谜。如何从零散的化石证据中还原古生物的真实面貌&#xff1f;如何理解关键演化节点的具体过程&#xff1f;10月23日&#xff0c;Science Robotics发表重磅综述&#xff0c;首次系统性提出"古生物启发…

WPS文档中的“等线”如何删除

如何删除“等线”占用的行如何删除表格之间的空行WPS文档中的“等线”是什么如果删除脚注文本占用的行 如下这种&#xff0c;在文档中添加了表格和脚注&#xff0c;发现上下表格之间有多行空行&#xff0c;鼠标选中&#xff0c;显示是“等线”&#xff0c;那么如何去除等线占用…

开源办公软件OnlyOffice的使用教程以及8.2版本的更新功能测评

OnlyOffice 8.2 是一款功能全面的在线办公套件&#xff0c;在实际使用中&#xff0c;PDF协作编辑功能给我留下了深刻印象&#xff0c;让团队成员能够轻松共同编辑PDF并签署文档。这些改进不仅增强了协作效率&#xff0c;也让办公体验更加流畅和高效。如果你的团队需要一个集协作…

C/C++/PYTHON 改变 console terminal cmd 字体输出颜色

C代码 #include <stdio.h>// 定义一些常用颜色的转义序列 #define RED "\x1b[31m" #define GREEN "\x1b[32m" #define YELLOW "\x1b[33m" #define BLUE "\x1b[34m" #define RESET "\x1b[0m"int main() {// 在控制台输…

数据分析反馈:提升决策质量的关键指南

内容概要 在当今快节奏的商业环境中&#xff0c;数据分析与反馈已成为提升决策质量的重要工具。数据分析不仅能为企业提供全面的市场洞察&#xff0c;还能帮助管理层深入了解客户需求与行为模式。掌握数据收集的有效策略和工具&#xff0c;企业能够确保获得准确且相关的信息&a…