首发地址:https://www.cnblogs.com/saw96x/p/12465195.html

笔者也算是学了小半年的c++,之前都停留在控制台做做题,最近觉得这样实在是差点成就感,于是就想试试写一写简单的小游戏,在用打砖块,flappy bird等小游戏练练手后,在查阅书籍,查找一些网络资料后写了一个完成度还算高的空战小游戏的控制台应用,希望能对其他觉得迷茫的c++新手提供一些方向

游戏的完成效果:
先看看游戏的主要框架:

#include<iostream>
#include<cstdlib>
#include<conio.h>
#include<windows.h>
using namespace std;
//宏定义
#define High 15  //游戏界面高度
#define Width 25 //游戏界面宽度
#define EnemyNum 6 //敌机数量
//全局变量
int pos_x,pos_y; //飞机坐标
int canvas[High][Width]={0}; //背景画布,用二维数组表示
int enemy_x[EnemyNum],enemy_y[EnemyNum]; //敌机的坐标,因为有多架敌机,用一维数组表示
int BulletWidth; //子弹宽度,实现散弹功能
int EnemySpeed; //敌机速度,实现动态难度
int score; //得分复制代码
复制代码int main(){HideCursor();//隐藏光标startup();//游戏参数初始化while(1){//循环保持游戏进程show();//输出游戏画面UpdateWithoutInput();//与用户输入无关的数据更新UpdateWithInput();//与用户输入有关的数据更新}return 0;
}

大部分简单的游戏实现都可以依靠这类框架实现,还可以增加一个判断游戏是否进行函数作为循环条件,增加重新开始游戏的功能函数等等,这些就留给读者实现吧

让我们按顺序来看看这些函数的原理和实现方法吧

首先是隐藏光标函数,作为控制台应用,有个光标在屏幕乱闪肯定极其破坏游戏体验,那么就需要隐藏它。来看看这个函数长什么样:

void HideCursor(){CONSOLE_CURSOR_INFO cursor_info={1,0};SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cursor_info);
}

这个函数的原理呢,我也不知道,是在网上抄的,windows.h头文件的详细解析在网上笔者没有找到,如果读者能对其有所了解自然是再好不过了

然后是游戏参数的初始化,这个函数也毫无理解难度:

void startup(){pos_x=High-1; //x是纵坐标pos_y=Width/2;   //y是横坐标canvas[pos_x][pos_y]=1;  //在画布中飞机相应的位置设定值为1,表示这个位置是飞机for(int i=0;i<EnemyNum;i++){ //给每架敌机设定随机的出现位置enemy_y[i]=rand()%Width;enemy_x[i]=rand()%2;canvas[enemy_x[i]][enemy_y[i]]=3; //在画布中敌机相应的位置设定值为3,表示这个位置是敌机}score=0;BulletWidth=0;EnemySpeed=13; //速度其实是刷新的时间间隔,因此速度越小速度越快
}

接下来是输出游戏画面的函数了,算是重头戏:

void show(){gotoxy(0,0);  //让输出内容的光标回到左上角for(int i=0;i<High;i++){      //这两行是对画布元素值for(int j=0;j<Width;j++){ //逐一扫描if(canvas[i][j]==0) //如果值为0printf(" ");  //输出空格,表示空白else if(canvas[i][j]==1) //如果值为1printf("*"); //输出*,表示飞机else if(canvas[i][j]==2) //如果值为2printf("|"); //输出|,表示子弹else if(canvas[i][j]==3) //如果值为3printf("@"); //输出@,表示敌机}printf("\n"); //扫描完一行,换行开始下一行}printf("Score:%3d\n",score); //输出分数Sleep(20); //停留2毫秒,作为刷新频率
}

大概讲解一下输出画面的思路。首先将二维数组作为画布背景,其中的元素值代表画面上的游戏对象,如果值是0,就说明此处是空白;如果是1,代表是飞机;如果是2,代表是飞机发射的子弹;如果是3,代表是敌机。然后通过对此画布二维数组遍历,通过其值来判断输出的内容。那么怎么实现动画效果呢,当再一次调用此函数时,第一行的gotoxy(0,0)会将输出光标移动到窗口左上角,此时再次输出画面,就会实现其中元素的移动效果啦,gotoxy不是标准库函数,同样需要window.h来自己编写,具体原理不用管,直接copy使用就是了:

void gotoxy(int x,int y){HANDLE handle=GetStdHandle(STD_OUTPUT_HANDLE);COORD pos;pos.X=x;pos.Y=y;SetConsoleCursorPosition(handle,pos);
}

当然,只靠画面输出函数是无法实现游戏的动画效果的,还需要画布中数据的更新,于是就需要UpdateWithoutInput();(与用户输入无关的数据更新) UpdateWithInput();(与用户输入有关的数据更新)。先看看UpdateWithoutInput()的实现:

void UpdateWithoutInput(){for(int i=0;i<High;i++){     //这两个循环for(int j=0;j<Width;j++){//是逐一扫描画布元素if(canvas[i][j]==2){ //如果元素值是2(即子弹),会发生如下的数据改变for(int k=0;k<EnemyNum;k++){ //对每架敌机的相关数据进行遍历if(i==enemy_x[k]&&j==enemy_y[k]){ //如果子弹横纵坐标和敌机的相等score++;  //加分if(score<7&&EnemySpeed>2) EnemySpeed=13;//实现不同分数段难度不同else if(score>=7&&score<14) EnemySpeed=11;else if(score>=14&&score<21) EnemySpeed=9;else if(score>=21&&score<40) EnemySpeed=7;else if(score>=40&&score<60) EnemySpeed=5;else if(score>=60) EnemySpeed=3;if(score<15) BulletWidth=0; //如果分数小于15,子弹宽度为0,那么只有单发子弹else if(score<30&&score>=15) BulletWidth=1;//分数大于15小于30,宽度为1,那么有3发子弹else if(score<45&&score>=30) BulletWidth=2;//分数大于30小于45,宽度为2,那么有5发子弹canvas[enemy_x[k]][enemy_y[k]]=0; //既然子弹和敌机的坐标重合,那么敌机被消灭,相应的位置也就变为了空白enemy_x[k]=rand()%2; //随机出新的敌机的纵坐标enemy_y[k]=rand()%Width; //随机出新的敌机的横坐标canvas[enemy_x[k]][enemy_y[k]]=3; //生成新的敌机canvas[i][j]=0; //子弹消失(实际上子弹并未消失,笔者没搞出原因)}}canvas[i][j]=0;//令子弹的原位置为空白if(i>0)canvas[i-1][j]=2;//生成子弹的新位置数据,配合输出画面函数实现动画效果}}}static int speed=0;             //这俩句可能比较难懂,设置成静态变量是为了防止超出作用域后speed直接消失导致无法更新数据if(speed<EnemySpeed) speed++;   //设置speed的目的是只有当speed加到等于EnemySpeed时才更新在画布中移动的敌机的位置数据,从而实现敌机移动较慢的动画效果for(int k=0;k<EnemyNum;k++){ //对每架敌机都进行处理if(pos_x==enemy_x[k]&&pos_y==enemy_y[k]){ //敌机与飞机位置重合,游戏失败printf("You Lose!\n");Sleep(3000);system("pause");exit(0);    }if(enemy_x[k]>High){ //敌机飞出了范围canvas[enemy_x[k]][enemy_y[k]]=0; //将原位置置为空白enemy_y[k]=rand()%Width; //生成新的敌机坐标enemy_x[k]=rand()%2;canvas[enemy_x[k]][enemy_y[k]]=3; //生成新的敌机score--; //扣分}if(speed==EnemySpeed){  //speed等于EnemySpeed,可以更新敌机的位置数据了for(int i=0;i<EnemyNum;i++){canvas[enemy_x[i]][enemy_y[i]]=0;enemy_x[i]++; //纵坐标加1,向前移动speed=0;canvas[enemy_x[i]][enemy_y[i]]=3;}}}
}

这个函数可以说是主体了,输出画面函数配合数据的更新可以实现简单的动画效果,很多小游戏都可以用这种方法实现,如果能理解这种体系那么配合注释应该可以看懂,还是建议自己敲一遍加深理解

然后是与用户有关的操作了:

void UpdateWithInput(){char input;//输入字符if(_kbhit()){ //如果按动了键盘input=_getch();//读取键盘输入的字符if(input=='a'){ //如果输入的字符是a,那么向左移动,以下几个分支类同canvas[pos_x][pos_y]=0;pos_y--;canvas[pos_x][pos_y]=1;}else if(input=='w'){canvas[pos_x][pos_y]=0;pos_x--;canvas[pos_x][pos_y]=1;}else if(input=='s'){canvas[pos_x][pos_y]=0;pos_x++;canvas[pos_x][pos_y]=1;}else if(input=='d'){canvas[pos_x][pos_y]=0;pos_y++;canvas[pos_x][pos_y]=1;}else if(input==' '){  //如果读入的是空格键int l=pos_y-BulletWidth; //子弹流的左端int r=pos_y+BulletWidth; //子弹流的右端for(int k=l;k<=r;k++)  //输出一排子弹canvas[pos_x-1][k]=2;}}
}

这段也很简单,不多解释了

以下是完整代码:

#include<iostream>
#include<cstdlib>
#include<conio.h>
#include<windows.h>
using namespace std;#define High 15
#define Width 25
#define EnemyNum 6int pos_x,pos_y;
int canvas[High][Width]={0};
int enemy_x[EnemyNum],enemy_y[EnemyNum];
int BulletWidth;
int EnemySpeed;
int score;void gotoxy(int x,int y){HANDLE handle=GetStdHandle(STD_OUTPUT_HANDLE);COORD pos;pos.X=x;pos.Y=y;SetConsoleCursorPosition(handle,pos);
}
void HideCursor(){CONSOLE_CURSOR_INFO cursor_info={1,0};SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cursor_info);
}
void startup(){pos_x=High-1;pos_y=Width/2;canvas[pos_x][pos_y]=1;for(int i=0;i<EnemyNum;i++){enemy_y[i]=rand()%Width;enemy_x[i]=rand()%2;canvas[enemy_x[i]][enemy_y[i]]=3;}score=0;BulletWidth=0;EnemySpeed=13;
}
void show(){gotoxy(0,0);for(int i=0;i<High;i++){for(int j=0;j<Width;j++){if(canvas[i][j]==0)printf(" ");else if(canvas[i][j]==1)printf("*");else if(canvas[i][j]==2)printf("|");else if(canvas[i][j]==3)printf("@");}printf("\n");}printf("Score:%3d\n",score);Sleep(20);
}
void UpdateWithoutInput(){for(int i=0;i<High;i++){for(int j=0;j<Width;j++){if(canvas[i][j]==2){for(int k=0;k<EnemyNum;k++){if(i==enemy_x[k]&&j==enemy_y[k]){score++;if(score<7&&EnemySpeed>2) EnemySpeed=13;else if(score>=7&&score<14) EnemySpeed=11;else if(score>=14&&score<21) EnemySpeed=9;else if(score>=21&&score<40) EnemySpeed=7;else if(score>=40&&score<60) EnemySpeed=5;else if(score>=60) EnemySpeed=3;if(score<15) BulletWidth=0;else if(score<30&&score>=15) BulletWidth=1;else if(score<45&&score>=30) BulletWidth=2;canvas[enemy_x[k]][enemy_y[k]]=0;enemy_x[k]=rand()%2;enemy_y[k]=rand()%Width;canvas[enemy_x[k]][enemy_y[k]]=3;canvas[i][j]=0;}}canvas[i][j]=0;if(i>0)canvas[i-1][j]=2;}}}static int speed=0;if(speed<EnemySpeed) speed++;for(int k=0;k<EnemyNum;k++){if(pos_x==enemy_x[k]&&pos_y==enemy_y[k]){printf("You Lose!\n");Sleep(3000);system("pause");exit(0);    }if(enemy_x[k]>High){canvas[enemy_x[k]][enemy_y[k]]=0;enemy_y[k]=rand()%Width;enemy_x[k]=rand()%2;canvas[enemy_x[k]][enemy_y[k]]=3;score--;}if(speed==EnemySpeed){for(int i=0;i<EnemyNum;i++){canvas[enemy_x[i]][enemy_y[i]]=0;enemy_x[i]++;speed=0;canvas[enemy_x[i]][enemy_y[i]]=3;}}}
}
void UpdateWithInput(){char input;if(_kbhit()){input=_getch();if(input=='a'){canvas[pos_x][pos_y]=0;pos_y--;canvas[pos_x][pos_y]=1;}else if(input=='w'){canvas[pos_x][pos_y]=0;pos_x--;canvas[pos_x][pos_y]=1;}else if(input=='s'){canvas[pos_x][pos_y]=0;pos_x++;canvas[pos_x][pos_y]=1;}else if(input=='d'){canvas[pos_x][pos_y]=0;pos_y++;canvas[pos_x][pos_y]=1;}else if(input==' '){int l=pos_y-BulletWidth;int r=pos_y+BulletWidth;for(int k=l;k<=r;k++)canvas[pos_x-1][k]=2;}}
}int main(){HideCursor();startup();while(1){show();UpdateWithoutInput();UpdateWithInput();}return 0;
}

以后应该还会更新一些别的小游戏,可能还会用图形库更新这个游戏

PS:推荐阅读《C语言课程设计与游戏开发实践教程》,如果不知道C语言能干嘛就看看这本书吧!

空战小游戏(控制台应用) c/c++实现相关推荐

  1. C# 飞行棋小游戏 (控制台应用)

    目录 C# 控制台飞行棋小游戏 简要介绍 游戏画面 规则说明 游戏代码 `Entry.cs` `Operate.cs` `Map.cs` `Player.cs` 其他问题 C# 控制台飞行棋小游戏 简 ...

  2. C++制作简单的军棋小游戏(控制台窗口)

    一.游戏规则: 这款自己DIY的小游戏有24个棋子.其中司令,军长各1个:师长,旅长,团长,营长,炸弹各2个:连长,排长,工兵,地雷各3个.棋子由小到大的顺序是:司令>军长>师长>旅 ...

  3. Java小游戏:控制台版“恶龙咆哮“

    小白一枚:运行效果图奉上(将来本人也一定是一名大佬Java界的科学家) 备注:选择游戏难度 "噩梦" 还是很有 "挑战性" 的 !!! 游戏开始:!!! 游戏过 ...

  4. java走棋_Java五子棋小游戏(控制台纯Ai算法)

    Java五子棋小游戏(控制台纯Ai算法) 继续之前的那个五子棋程序 修复了一些已知的小Bug 这里是之前的五子棋程序 原文链接 修复了一些算法缺陷 本次增加了AI算法 可以人机对战 也可以Ai对Ai看 ...

  5. [娱乐]一款浅陋的C++控制台贪吃蛇小游戏

    因为时间有限,没能尽可能完善这一款贪吃蛇,不过能做出来还是很有意思的 1 #include<bits/stdc++.h> 2 #include<windows.h> 3 #in ...

  6. 如何用python开发游戏_手把手教你用Python完成一个控制台小游戏-阿里云开发者社区...

    很多人想学Python程序设计或者已经了解过一点Python程序设计基础,却没办法开发出一个项目. 今天,通过演示一个简单的控制台小游戏制作,手把手教你如何用Python编写一个游戏程序,即便你是个新 ...

  7. 基于C++控制台(Windows平台)的一个吃豆人小游戏

    PacManX --南京大学2019秋季学期 "高级程序设计 "课程设计一 基于C++控制台(Windows平台)的一个吃豆人小游戏 已实现的目标: 地图支持自定义编辑(可编辑地图 ...

  8. 基于控制台的五子棋小游戏(简易)

    基于控制台的五子棋小游戏(简易) 展示 源码: 使用: GoBang类: 展示 话不多说上代码 Don't talk much, say the code! 源码: 使用: new完直接运行 publ ...

  9. C语言 弹小球 小游戏(控制台)

    C语言实现弹小球游戏 编译环境:vs2019 需求: 小球在控制台界面内不停移动,碰到边界则改变方向,控制棍子接住小球,得分加一,小球没有被接住则游戏结束. 思路: _getch()函数接收a.d两个 ...

最新文章

  1. layui 数据表格内容过长遮挡_word表格技巧:遇到这三种情况,你会处理么?
  2. mysql开启binlog
  3. 华宇输入法linux,华宇拼音输入法DEB版能切换为五笔输入法,附操作方法
  4. NYOJ72Financial Management
  5. android学习资料
  6. 初探云原生应用管理(二): 为什么你必须尽快转向 Helm v3
  7. 你不就是加了 2 行代码,为什么要用 2 天?
  8. vue 带全选和多选的表格怎么写_vue+element-ui里面table组件多选框实现批量操作
  9. 差异表达基因变化倍数_2020年筛个基因也还能发SCI?
  10. php判断平年和闰年,平年和闰年的三种判断方法
  11. ROS学习笔记13(测试一个简单的消息发布和消息订阅)
  12. MySQL安装包下载及配置方法
  13. 威纶触摸屏使用说明书_你不知道选择工业触摸屏还有这么多技巧?
  14. 35岁的程序员:第25章,离职
  15. Windows Server 2008 R2将tomcat添加进系统服务
  16. 使用docker运行mysql:5.7
  17. 小功能⭐️Untiy组合键检测
  18. 【3D目标检测】学习过的论文整理
  19. 我说CMMI之五:CMMI 4个等级的区别
  20. Hive性能优化(全面)解决数据倾斜等问题

热门文章

  1. 安卓手机使用NFC读取MifareClassic等标签信息
  2. synchronized详解
  3. Python打包文件到exe 修改图标 优化启动速度
  4. 职称计算机ppt2003大纲,全国职称计算机考试PowerPoint2003考试大纲
  5. c语言 设置windows2008,调教Windows server 2008系统菜单
  6. 安卓虚拟机上用charles+drony抓包app的websocket
  7. go-ElasticSearch实战篇(二)
  8. 无人值守污水处理控制系统。 西门子200PLC和显控触摸屏编写的智能污水处理控制系统
  9. javaScript移动端相册
  10. PorterDuffXfermode 图像混合技术在漫画APP中的应用