【C++】做一个飞机空战小游戏(三)——getch()函数控制任意造型飞机图标移动

本文主要是介绍【C++】做一个飞机空战小游戏(三)——getch()函数控制任意造型飞机图标移动,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

   [导读]本系列博文内容链接如下:

【C++】做一个飞机空战小游戏(一)——使用getch()函数获得键盘码值

【C++】做一个飞机空战小游戏(二)——利用getch()函数实现键盘控制单个字符移动
【C++】做一个飞机空战小游戏(三)——getch()函数控制任意造型飞机图标移动

【C++】做一个飞机空战小游戏(四)——给游戏添加背景音乐(多线程技巧应用)

【C++】做一个飞机空战小游戏(五)——getch()控制两个飞机图标移动(控制光标位置)

【C++】做一个飞机空战小游戏(六)——给两架飞机设置不同颜色(cout输出彩色字符、结构体使用技巧)

【C++】做一个飞机空战小游戏(七)——两组按键同时检测平滑移动(GetAsyncKeyState()函数应用)

【C++】做一个飞机空战小游戏(八)——生成敌方炮弹(rand()函数应用)

【C++】做一个飞机空战小游戏(九)——发射子弹的编程技巧

【C++】做一个飞机空战小游戏(十)——子弹击落炮弹、炮弹与飞机相撞 

在前两讲当中,介绍了利用getch()函数实现了对单一字符图标的移动控制。今天要实现对于复杂图标的移动控制,经过分析发现前两讲中的程序当中还有些不够合理的地方。主要有以下几方面:

第一,主函数main()中包含了很多if语句、for循环、case语句这类的程序片段,主函数显得非常凌乱,程序的可移植性可扩展性太差;第二,程序当中编写了一个showplane函数,有了模块化的运用,但是这个函数也是在main函数所在的cpp文件中,程序的模块化程度不够高;第三,飞机图标的显示函数只适用于单个字符,要想换一个稍微复杂点的图标,就需要修改showplane函数内部代码,函数的通用性太差。

要想解决以上三方面存在的问题,就需要采用模块化设计思路,使程序结构性更强,可读性可移植性更好,也有利于多人协作共同开发,提高程序开发效率。

目录

一、什么是模块化程序设计

二、c++实现模块化设计的方法

(一)函数

(二)头文件

(三)功能函数定义文件(cpp文件)

三、本例的设计思路

(一)程序流程图

(二)头文件

(三)主函数

(四)功能函数库

1、初始化函数

2、获取键盘指令函数key()

3、计算飞机图标实时坐标函数

4、显示飞机图标函数showplane()

5、功能函数完整文件control_plane.cpp

四、项目文件

五、运行效果


一、什么是模块化程序设计

模块化程序设计是指在进行程序设计时将一个大程序按照功能划分为若干小程序模块,每个小程序模块完成一个确定的功能,并在这些模块之间建立必要的联系,通过模块的互相协作完成整个功能的程序设计方法。

在设计较复杂的程序时,一般采用自顶向下的方法,将问题划分为几个部分,各个部分再进行细化,直到分解为较好解决问题为止。模块化设计,简单地说就是程序的编写不是一开始就逐条录入计算机语句和指令,而是首先用主程序、子程序、子过程等框架把软件的主要结构和流程描述出来,并定义和调试好各个框架之间的输入、输出链接关系逐步求精的结果是得到一系列以功能块为单位的算法描述。以功能块为单位进行程序设计,实现其求解算法的方法称为模块化。模块化的目的是为了降低程序复杂度,使程序设计、调试和维护等操作简单化。利用函数,不仅可以实现程序的模块化,使得程序设计更加简单和直观,从而提高了程序的易读性和可维护性,而且还可以把程序中经常用到的一些计算或操作编写成通用函数,以供随时调用。

二、c++实现模块化设计的方法

c++实现模块化设计的主要方法有两种,一种是利用类,另外一种就是函数及头文件。类涉及的内容比较多,暂时先不讲,只简单介绍下函数和头文件的使用。

(一)函数

每个函数实现一种特定的功能,是一个小功能模块,函数之间可以通过形参或者全局变量进行信息的交互。在主函数内,调用具体功能函数来实现一定的控制目的,主函数内的语句非常少,具体的代码都在各个功能函数之中。

函数根据有无返回值分为两种,一种是有返回值的,另外一种是无返回值的,有返回值的,声明函数时需要声明函数(也就是返回值)的数据类型,函数调用后,要将运算的结果返回,无返回值的函数类型为void,函数调用后只执行了一些动作,没有运算结果,或无需将运算的结果返回。

函数可以有形式参量,如果有,则需要声明和定义函数时,同时声明形参的数据类型。函数也可以没有形式参量,用void来表示。

(二)头文件

头文件中一般包含两类内容,一类是全局变量,一类是全局函数。注意,头文件中只声明函数,不定义函数的具体内容。

(三)功能函数定义文件(cpp文件)

这类文件中没有主函数,只有各个功能函数的具体定义,一个文件里可以有多个功能函数。

主函数中要想引用头文件中声明的变量和函数,需要在文件中标明#include "头文件名.h"。

三、本例的设计思路

本例中由键盘控制飞机移动,程序主体由5个功能模块组成:初始化、清屏、显示飞机图标、获取键盘指令、计算飞机新的坐标。

(一)程序流程图

程序流程图如图1所示。

图1 程序流程图

(二)头文件

头文件control_plane.h具体内容如下所示。

#ifndef CONTROL_PLANE_H
#define CONTROL_PLANE
#include <iostream>
#include <string>
using namespace std;#define tb 0  	//图形显示区域上侧边界 
#define lb 0	//图形显示区域左侧边界
#define rb 100	//图形显示区域右侧边界
#define bb 20	//图形显示区域下侧边界//定义飞机造型 
const string icon_plane[]={"  ■ ","■■■","■■■"};//定义图标坐标结构体 
typedef struct{int x;int y;
} location;//定义移动方向命令枚举类型 
typedef  enum {up_cmd,down_cmd,left_cmd,right_cmd} direction_cmd;extern location plocation;			//声明飞机坐标 
static direction_cmd dir_cmd; 		//声明存放按键码值的两个变量//声明刷新飞机位置函数 
void show_plane(location plct);//获取键盘指令 
direction_cmd key(void);//计算出接收指令后的飞机坐标 
location plane_locate(location plct,direction_cmd dircmd);void init(void); #endif

注意:本飞机造型可以自定义,只需要改变string icon_plane[]的内容即可,字符串数组变量中,每一个元素是飞机造型的一行,一个空格占1位,一个方格占2位。

(三)主函数

主函数要引入定义的头文件control_plane.h,声明了一个外部全局变量plocation,类型为头文件中定义的location型,用于存放飞机的坐标。本例中的main函数带有两个参量int argc, char** argv,这个是以新建项目的方法创建的,两个参数自己生成的,具体含义可自行搜素其他相关文章。

主函数的内容与程序流程图一致,一共调用了5个函数,除system("cls")为系统函数外,init(),show_plane(),key(),plane_locate()4个函数都是自定义功能函数。

#include <iostream>
#include "control_plane.h"
#include <string>
using namespace std;location plocation;int main(int argc, char** argv) {	init();						//初始化 while(1)					//循环等待键盘指令 {system("cls");			//清屏show_plane(plocation);	//刷新飞机图标 		dir_cmd=key();			//获取按键指令 //计算收到键盘指令后的飞机坐标 plocation=plane_locate(plocation,dir_cmd);		}return 0; 	
}

(四)功能函数库

主函数中调用的4个功能函数都在control_plane.h头文件声明,在control_plane.app文件中定义。

1、初始化函数

本函数为无参无返回值函数,具体代码如下:

//初始化函数 
void init(void)
{plocation.x=rb/2;				//初始化飞机图标的x坐标为屏幕横轴最大值的一半 plocation.y=bb;					//初始化飞机图标的y坐标为屏幕纵轴最大值
}

2、获取键盘指令函数key()

本函数是无参函数,根据键盘的指令,判断出控制方向的意图,返回值为枚举类型。direction_cmd在头文件中进行了声明和定义。key()函数的具体代码如下:

//获取键盘指令函数 
direction_cmd key(void)
{int key_value1,key_value2;			//声明两个变量,存放键值 key_value1=getch();					//先获取第一个码值 if(key_value1==224)					//如果第一个码值为224,则进行第二个码值的判断 {key_value2=getch();			//先获取第二个码值switch(key_value2){case 72:				//向上方向键 return up_cmd;case 80:				//向下方向键return down_cmd;case 75:				//向左方向键return left_cmd;case 77:				//向右方向键return right_cmd;}}		
}

3、计算飞机图标实时坐标函数

location plane_locate(location plct,direction_cmd dircmd),有三个参量,plct是获得移动指令之前的位置坐标,dircmd是移动方向指令。函数返回值是一个结构体形式的location类型数据。

//计算获得移动指令后飞机的坐标 
location plane_locate(location plct,direction_cmd dircmd)
{int x,y;x=plct.x;y=plct.y;switch(dircmd){case up_cmd:y--;				//字符上移一行,行值y减1if(y<tb)			//限定y值最小值为0{y=tb;}break;case down_cmd:y++;				//字符下移一行,行值y加1if(y>bb)			//限定y高度 {y=bb;}break;case left_cmd:x--;				//字符左移一列,列值x减1if(x<lb){x=lb;			//限定x最小值为0; }break;case right_cmd:x++;				//字符右移一列,列值x加1if(x>rb){x=rb;			//限定x宽度}break;}plct.x=x;plct.y=y;return plct;}

4、显示飞机图标函数showplane()

void show_plane(location plct),有一个参量,是飞机图标在获取移动指令后的坐标值。函数的作用是刷新飞机图标,无返回值。

//飞机图标刷新函数 
void show_plane(location plct)		//预先定义字符定位显示函数,x是列坐标,y是行坐标,原点(x=0,y=0)位于屏幕左上角 
{int x,y;int i,j;	int rows=sizeof(icon_plane)/sizeof(icon_plane[0]);x=plct.x;y=plct.y;	for(j=0;j<y;j++)				//图标上侧输出y个换行符{cout<<endl;}for(i=0;i<rows;i++)				//图标每行前输出x个空格 {for(j=0;j<x;j++){cout<<" ";}cout<<icon_plane[i]<<endl;}
}

5、功能函数完整文件control_plane.cpp

#include <iostream>
#include "conio.h"
#include <string>
#include "control_plane.h"
using namespace std;//初始化函数 
void init(void)
{plocation.x=rb/2;				//初始化飞机图标的x坐标为屏幕横轴最大值的一半 plocation.y=bb;					//初始化飞机图标的y坐标为屏幕纵轴最大值
}//飞机图标刷新函数 
void show_plane(location plct)		//预先定义字符定位显示函数,x是列坐标,y是行坐标,原点(x=0,y=0)位于屏幕左上角 
{int x,y;int i,j;	int rows=sizeof(icon_plane)/sizeof(icon_plane[0]);x=plct.x;y=plct.y;	for(j=0;j<y;j++)				//图标上侧输出y个换行符{cout<<endl;}for(i=0;i<rows;i++)				//图标每行前输出x个空格 {for(j=0;j<x;j++){cout<<" ";}cout<<icon_plane[i]<<endl;}
}//获取键盘指令函数 
direction_cmd key(void)
{int key_value1,key_value2;			//声明两个变量,存放键值 key_value1=getch();					//先获取第一个码值 if(key_value1==224)					//如果第一个码值为224,则进行第二个码值的判断 {key_value2=getch();			//先获取第二个码值switch(key_value2){case 72:				//向上方向键 return up_cmd;case 80:				//向下方向键return down_cmd;case 75:				//向左方向键return left_cmd;case 77:				//向右方向键return right_cmd;}}		
}//计算获得移动指令后飞机的坐标 
location plane_locate(location plct,direction_cmd dircmd)
{int x,y;x=plct.x;y=plct.y;switch(dircmd){case up_cmd:y--;				//字符上移一行,行值y减1if(y<tb)			//限定y值最小值为0{y=tb;}break;case down_cmd:y++;				//字符下移一行,行值y加1if(y>bb)			//限定y高度 {y=bb;}break;case left_cmd:x--;				//字符左移一列,列值x减1if(x<lb){x=lb;			//限定x最小值为0; }break;case right_cmd:x++;				//字符右移一列,列值x加1if(x>rb){x=rb;			//限定x宽度}break;}plct.x=x;plct.y=y;return plct;}

四、项目文件

由于本例中用到了自定义函数和头文件,需要新建项目,并把主函数、自定义函数库和头文件都加载进来。项目布局截图如下图所示。

图2 项目布局截图

五、运行效果

图3 运行效果图

再试着变换一下飞机造型,做一个更复杂的造型,只需要把飞机造型变量更改一下即可,如下图。

//定义飞机造型 
const string icon_plane[]={"    ■   ","■  ■  ■","■■■■■","■  ■  ■","    ■   ","  ■■■ "};

飞机的造型即可变为如下所示。

(未完待续)

这篇关于【C++】做一个飞机空战小游戏(三)——getch()函数控制任意造型飞机图标移动的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/349143

相关文章

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

【C++ Primer Plus习题】13.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "port.h"int main() {Port p1;Port p2("Abc", "Bcc", 30);std::cout <<

C++包装器

包装器 在 C++ 中,“包装器”通常指的是一种设计模式或编程技巧,用于封装其他代码或对象,使其更易于使用、管理或扩展。包装器的概念在编程中非常普遍,可以用于函数、类、库等多个方面。下面是几个常见的 “包装器” 类型: 1. 函数包装器 函数包装器用于封装一个或多个函数,使其接口更统一或更便于调用。例如,std::function 是一个通用的函数包装器,它可以存储任意可调用对象(函数、函数

hdu1171(母函数或多重背包)

题意:把物品分成两份,使得价值最接近 可以用背包,或者是母函数来解,母函数(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v) 其中指数为价值,每一项的数目为(该物品数+1)个 代码如下: #include<iostream>#include<algorithm>

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

06 C++Lambda表达式

lambda表达式的定义 没有显式模版形参的lambda表达式 [捕获] 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 有显式模版形参的lambda表达式 [捕获] <模版形参> 模版约束 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 含义 捕获:包含零个或者多个捕获符的逗号分隔列表 模板形参:用于泛型lambda提供个模板形参的名

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

【C++高阶】C++类型转换全攻略:深入理解并高效应用

📝个人主页🌹:Eternity._ ⏩收录专栏⏪:C++ “ 登神长阶 ” 🤡往期回顾🤡:C++ 智能指针 🌹🌹期待您的关注 🌹🌹 ❀C++的类型转换 📒1. C语言中的类型转换📚2. C++强制类型转换⛰️static_cast🌞reinterpret_cast⭐const_cast🍁dynamic_cast 📜3. C++强制类型转换的原因📝