显示界面如上图所示

自己找的背景和飞机素材,先将素材奉上.

接下来我先简单分析一下这个单机游戏的运行逻辑:

就像显示界面所显示的那样,我们想要实现的是自己的飞机在发射子弹(子弹在上图没显示),然后当子弹射到敌方飞机,这里设置了两种类型的飞机,如果读者想定义更多类型的,直接添加属性就可以.当子弹射到飞机的时候,飞机的血量减少,就像CS一样,并不一定是一发子弹就死亡,读者可以根据自己喜欢去设置,博主这里设置大飞机的血量是3发子弹,而小飞机的血量是1发子弹,也就是说,当有3发子弹射到大飞机的时候,大飞机就消失,一发子弹小飞机消失.至于其他的动态效果,博主这里暂时不做介绍.具体往下看:

面向对象开发,每一个对象我们都需要给他设置相对应的对象属性,在语言当中,我们将其设置成结构体就可以:

enum My
{WIDTH = 500,HIGHT = 700,BULLET_NUM = 100,//玩家子弹数量ENEMY_NUM = 10,//敌机的数量BIG,SMALL,
};
struct Plane
{int x;int y;bool live;//是否存活int width;int hight;int hp;int type;//敌机类型  big small}player,bull[BULLET_NUM],enemy[ENEMY_NUM];

首先设定了一个联合,用于设置弹出窗口的基本参数和其他属性.

上面是不是把敌方飞机,自己飞机和自己发射的子弹都定义成了一个结构体.下面我们就可以直接用了.

(x,y)代表的是对象在窗口当中的坐标,width和hight是对象自身的尺寸,而hp是血量,type是博主自己定义了两种敌机类型.布尔类型live判断飞机是否存活状态.

第一步我们应该是要先创建图形窗口

 /*测试
circle(50, 50, 50);//画空心圆
setfillcolor(GREEN);//圆的颜色
fillcircle(100, 100, 50);///实心⚪*///创建图形窗口initgraph(WIDTH, HIGHT,SHOWCONSOLE);//宽长

initgraph()函数直接用

第二步加载窗口里面使用到的图片   //无论什么时候用,我们都要进行图片加载的,因此此处我们将其设定到一个函数下,方便之后也可以随时添加和删除.

//把图片加载进程序
IMAGE bk;//背景图
//保存玩家图片
IMAGE img_role;
//保存子弹
IMAGE img_bull;
//
IMAGE img_enemy[4];
void loadImg()
{//加载图片loadimage(&bk, "D:/program/飞机大战/images/bk.png");//加载玩家图片loadimage(&img_role, "D:/program/飞机大战/images/fly.png");//加载子弹图片loadimage(&img_bull, "D:/program/飞机大战/images/子弹.jpg");//加载敌机的图片loadimage(&img_enemy[0], "D:/program/飞机大战/images/enemy1.png");loadimage(&img_enemy[1], "D:/program/飞机大战/images/enemy2.png");//loadimage(&img_enemy[2], "D:/program/飞机大战/images/enemy3.jpg");//loadimage(&img_enemy[3], "D:/program/飞机大战/images/enemy4.jpg");
}

IMAGE 是easyx里面的一个参数,直接用

此案例当中,需要我们加载的图片有背景图,自己飞机图,子弹图,敌方飞机1和敌方飞机2,如果读者也自己添加第三台和第四台敌机,也可以直接添加,不过要注意,当一种对象,存在多个类型的时候,要采用数组将其存储,方便之后进行使用.

第三步,要干嘛?设置好窗口了,加载完图片了,是不是要把图片添加进去了?

那图片添加到哪里去?怎么添加?哪一种图片应该添加在哪里呢?

这里我们是不是首先要初始化一下图片的基本属性?of course,买衣服我总的知道我适合穿多大尺码的衣服吧?

void gameinit()//初始化数据
{player.x = WIDTH / 2;player.y = HIGHT - 120;player.live = true;//初始化子弹for (int i = 0; i < BULLET_NUM; i++){bull[i].x = 0;bull[i].y = 0;bull[i].live = false;}//初始化敌机for (int i = 0; i < ENEMY_NUM; i++){enemy[i].live = false;enemyHP(i);}
}

想想我们一共有几个对象,去除背景图片不需要我们在这里初始化之外,另外就是自己飞机,敌方飞机和子弹三个对象.那么我们就定义一个函数,用于初始化这些对象的第一属性.

在初始化敌方飞机的时候,博主之前把敌方飞机设置有两种类型,那么这两种类型飞机的基本属性一定有一些是不一样的呀,要不然怎么叫做2呢?

博主这里主要用飞机的大小和血量来区分这两种飞机.具体看enemyHP()函数

void enemyHP(int i)
{int flag = rand() % 10;if (flag>=0 && flag<=2)//0-9{enemy[i].type = BIG;enemy[i].hp = 3;enemy[i].width = 100;enemy[i].hight = 100;}else{enemy[i].type = SMALL;enemy[i].hp = 1;enemy[i].width = 50;enemy[i].hight = 50;}}

在这个函数当中,我们要注意,大飞机和小飞机出现的次数是不是正常情况下是不一样的?比如小飞机出现了5次,而大飞机才出现一次这样,当然敌飞机出现肯定不是我们可以控制的,它肯定是随机出现的,所以这里我们采用一个随机范围,如果在0-2之间就出现大飞机,3-9之间小飞机,这样是不是小飞机的概率要高于大飞机.其余的进入条件之内直接初始化就可以了.

第四步,上面我们把全部图片都加载好,然后对象都进行了初始化,接下来我们要干嘛?

那肯定是要将这些图片绘制到对应的窗口坐标上了!!!!!!!

void gameDraw()
{loadImg();//把背景贴在窗口上putimage(0, 0, &bk);putimage(player.x, player.y, &img_role,SRCINVERT);for (int i = 0; i < BULLET_NUM; i++){if (bull[i].live){putimage(bull[i].x, bull[i].y, &img_bull, SRCINVERT);}}//绘制敌机for (int i = 0; i < ENEMY_NUM; i++){if (enemy[i].live){if(enemy[i].type==SMALL)putimage(enemy[i].x, enemy[i].y, &img_enemy[0], SRCINVERT);//x和y是飞机在窗口中的坐标elseputimage(enemy[i].x, enemy[i].y, &img_enemy[1], SRCINVERT);}}}

绘制背景,绘制自己飞机,绘制子弹,绘制敌方飞机都采用putimage()函数就可以了

需要注意的有可能就是对于敌方飞机和子弹只有live是true的时候才绘制,而对于敌方飞机还区分了两种类型的飞机,加一个if-else输出对应的敌方飞机就可以了;

第五步,第四步我们绘制的图片是个啥,是初始化的位置,是一个静态的图,我们要实现的动态图,那接下来我们应该干嘛????????

当然是让子弹,自己飞机和敌方飞机都动起来了,也就是创建动画

首先让自己飞机动起来

void playermove(int speed)
{
#if 0if (_kbhit) {//有两种方式//1,getch()  阻塞函数,和scanf一样,如果没有输入,就会卡住程序,一直等待输入,//这个函数不是c语言标准函数,需要头文件<conio.h>char key = _getch();switch (key){case 'w':case 'W':player.y -= speed;break;case 's':case 'S':player.y += speed;break;case 'a':case 'A':player.x -= speed;break;case 'd':case 'D':player.x += speed;break;default:break;}}
}
#elif 1//2.使用Windows函数获取键盘输入//非阻塞函数,特别流畅//如果用字母,必须要用大写,大写可以识别大小写if (GetAsyncKeyState(VK_UP) || GetAsyncKeyState('W')){if(player.y > 0)player.y -= speed;}if (GetAsyncKeyState(VK_DOWN) || GetAsyncKeyState('S')){if (player.y < HIGHT-78)//78是飞机的高度player.y += speed;}if (GetAsyncKeyState(VK_LEFT) || GetAsyncKeyState('A')){if(player.x+59>0)// 119/2  = 59是控制飞机子弹在左右边界的时候可以打到敌机player.x -= speed;}if (GetAsyncKeyState(VK_RIGHT) || GetAsyncKeyState('D')){if (player.x-59 < WIDTH-119)//119是飞机的宽度player.x += speed;}
#endif // 0if (GetAsyncKeyState(VK_SPACE) && Timer(100,1))//{//创建一个子弹createBullet();}}

这里尝试了两种让自己飞机动起来的方法,第一种是_kbhit,如果按下键盘,判断按下的是什么键,如果wsad当中的一个则执行对应的操作,但是这种方法运行之后,你会发现很卡,就是一个帧当中只能运行一个动作,不能运行右上这样的操作,关键是很卡

所以我们用了第二种方案非阻塞函数GetAsyncKeyState(),分别对键盘当中的上下左右和英文字符当中的wasd进行case分析,其他不变,此处要注意的有可能就是要控制自己的飞机运行,只能在窗口范围内运行,为其设定边界就可以.

最后还加了一个和子弹相关的函数,如果说按下空格键了,就要发射子弹了,同时这里结合了一个定时器的函数,用于控制子弹发射的速度100ms,不要再100ms内发射两颗子弹,防止出现子弹重叠的现象.

bool Timer(int ms, int id)//定时器
{static DWORD t[10];if (clock() - t[id] > ms){t[id] = clock();return true;}return false;
}

定义了一个无符号长整形的时间数组,是因为本案例当中有多个函数都用到了定时器函数.

自己飞机动起来,接下来就很明显了,让子弹跟着发射,对不对????也就是进入createBullet()函数

void createBullet()
{for (int i = 0; i < BULLET_NUM; i++){if (!bull[i].live){bull[i].x = player.x+59;bull[i].y = player.y;bull[i].live = true;break;}}
}

刚开始子弹都是的状态都是false,然后条件正确后,初始化了子弹的第一个位置发射出来,然后将子弹的状态改为true.跳出这一个,执行下一个,要注意此时只是静态化绘制了子弹,还没有动起来,那么接下来就让子弹垂直向上运行就好.

void Bullmove(int speed)
{for (int i = 0; i < BULLET_NUM; i++){if (bull[i].live){bull[i].y -=speed;if (bull[i].y < 0){bull[i].live = false;}}}
}

如果子弹到了最上方了,改变子弹的状态为false,继续循环

自己飞机和子弹都结束了,接下来就是敌方飞机了

//产生敌机
void createenemy()
{for (int i = 0; i < ENEMY_NUM; i++){if (!enemy[i].live){enemy[i].live = true;enemy[i].x = rand()%(WIDTH-75);enemy[i].y = 0;enemyHP(i);printf("pos(%d,%d) %d %d\n", enemy[i].x, enemy[i].y, enemy[i].live, enemy[i].hp);break;}}
}

在窗口的最上面随机产生敌机,敌机也要动的.是不是参考子弹的就可以了,如下

//敌机的移动
void enemymove(int speed)
{for (int i = 0; i < ENEMY_NUM; i++){if (enemy[i].live){enemy[i].y += speed;if (enemy[i].y > HIGHT){enemy[i].live = false;}}}
}

最后就是打飞机,当子弹到了敌方飞机的范围内是,敌方飞机就消失

//开始打飞机
void playplane()
{for (int i = 0; i < ENEMY_NUM; i++){if (!enemy[i].live)continue;for (int k = 0; k < BULLET_NUM; k++){if (!bull[k].live)continue;if (bull[k].x > enemy[i].x && bull[k].x<enemy[i].x + enemy[i].width&& bull[k].y>enemy[i].y && bull[k].y < enemy[i].y + enemy[i].hight)//子弹在飞机的界面内//则代表子弹打住了飞机{bull[k].live = false;enemy[i].hp--;}}if (enemy[i].hp == 0){enemy[i].live = false;}}
}
            if (bull[k].x > enemy[i].x && bull[k].x<enemy[i].x + enemy[i].width&& bull[k].y>enemy[i].y && bull[k].y < enemy[i].y + enemy[i].hight)//子弹在飞机的界面内//则代表子弹打住了飞机

这是个啥?意思是当子弹到了敌方飞机那个矩形图之内,条件就正确

这里要注意大飞机血量是3,小飞机血量是1,一颗子弹一格血量.当血量为0,则飞机死亡

最后一步,上主函数

int main()
{/*测试
circle(50, 50, 50);//画空心圆
setfillcolor(GREEN);//圆的颜色
fillcircle(100, 100, 50);///实心⚪*///创建图形窗口initgraph(WIDTH, HIGHT,SHOWCONSOLE);//宽长gameinit();//双缓冲绘图BeginBatchDraw();while (1){gameDraw();FlushBatchDraw();playermove(5);Bullmove(5);//防止飞机全部一起出来if (Timer(500,0)){//创建一个飞机createenemy();}if (Timer(20, 2)){enemymove(1);}playplane();}EndBatchDraw();return 0;
}

注意这里的

//双缓冲绘图BeginBatchDraw();EndBatchDraw();

是easyx插件里面的一个双缓冲绘图,防止图片在窗口当中出现闪屏

总代码:

#include<stdio.h>
//图形库,帮助我们新手,快速入门图形编程easyx
#include<graphics.h>
#include<conio.h>
#include<time.h>
enum My
{WIDTH = 500,HIGHT = 700,BULLET_NUM = 100,//玩家子弹数量ENEMY_NUM = 10,//敌机的数量BIG,SMALL,
};
struct Plane
{int x;int y;bool live;//是否存活int width;int hight;int hp;int type;//敌机类型  big small}player,bull[BULLET_NUM],enemy[ENEMY_NUM];//把图片加载进程序
IMAGE bk;//背景图
//保存玩家图片
IMAGE img_role;
//保存子弹
IMAGE img_bull;
//
IMAGE img_enemy[4];void loadImg()
{//加载图片loadimage(&bk, "D:/program/飞机大战/images/bk.png");//加载玩家图片loadimage(&img_role, "D:/program/飞机大战/images/fly.png");//加载子弹图片loadimage(&img_bull, "D:/program/飞机大战/images/子弹.jpg");//加载敌机的图片loadimage(&img_enemy[0], "D:/program/飞机大战/images/enemy1.png");loadimage(&img_enemy[1], "D:/program/飞机大战/images/enemy2.png");//loadimage(&img_enemy[2], "D:/program/飞机大战/images/enemy3.jpg");//loadimage(&img_enemy[3], "D:/program/飞机大战/images/enemy4.jpg");
}
bool Timer(int ms, int id)//定时器
{static DWORD t[10];if (clock() - t[id] > ms){t[id] = clock();return true;}return false;
}
void enemyHP(int i)
{int flag = rand() % 10;if (flag>=0 && flag<=2)//0-9{enemy[i].type = BIG;enemy[i].hp = 3;enemy[i].width = 100;enemy[i].hight = 100;}else{enemy[i].type = SMALL;enemy[i].hp = 1;enemy[i].width = 50;enemy[i].hight = 50;}}void gameinit()//初始化数据
{player.x = WIDTH / 2;player.y = HIGHT - 120;player.live = true;//初始化子弹for (int i = 0; i < BULLET_NUM; i++){bull[i].x = 0;bull[i].y = 0;bull[i].live = false;}//初始化敌机for (int i = 0; i < ENEMY_NUM; i++){enemy[i].live = false;enemyHP(i);}
}
//游戏绘制函数
void gameDraw()
{loadImg();//把背景贴在窗口上putimage(0, 0, &bk);putimage(player.x, player.y, &img_role,SRCINVERT);for (int i = 0; i < BULLET_NUM; i++){if (bull[i].live){putimage(bull[i].x, bull[i].y, &img_bull, SRCINVERT);}}//绘制敌机for (int i = 0; i < ENEMY_NUM; i++){if (enemy[i].live){if(enemy[i].type==SMALL)putimage(enemy[i].x, enemy[i].y, &img_enemy[0], SRCINVERT);//x和y是飞机在窗口中的坐标elseputimage(enemy[i].x, enemy[i].y, &img_enemy[1], SRCINVERT);}}}void createBullet()
{for (int i = 0; i < BULLET_NUM; i++){if (!bull[i].live){bull[i].x = player.x+59;bull[i].y = player.y;bull[i].live = true;break;}}
}
void Bullmove(int speed)
{for (int i = 0; i < BULLET_NUM; i++){if (bull[i].live){bull[i].y -=speed;if (bull[i].y < 0){bull[i].live = false;}}}
}//角色移动,获取键盘信息,上下左右
void playermove(int speed)
{
#if 0if (_kbhit) {//有两种方式//1,getch()  阻塞函数,和scanf一样,如果没有输入,就会卡住程序,一直等待输入,//这个函数不是c语言标准函数,需要头文件<conio.h>char key = _getch();switch (key){case 'w':case 'W':player.y -= speed;break;case 's':case 'S':player.y += speed;break;case 'a':case 'A':player.x -= speed;break;case 'd':case 'D':player.x += speed;break;default:break;}}
}
#elif 1//2.使用Windows函数获取键盘输入//非阻塞函数,特别流畅//如果用字母,必须要用大写,大写可以识别大小写if (GetAsyncKeyState(VK_UP) || GetAsyncKeyState('W')){if(player.y > 0)player.y -= speed;}if (GetAsyncKeyState(VK_DOWN) || GetAsyncKeyState('S')){if (player.y < HIGHT-78)//78是飞机的高度player.y += speed;}if (GetAsyncKeyState(VK_LEFT) || GetAsyncKeyState('A')){if(player.x+59>0)// 119/2  = 59是控制飞机子弹在左右边界的时候可以打到敌机player.x -= speed;}if (GetAsyncKeyState(VK_RIGHT) || GetAsyncKeyState('D')){if (player.x-59 < WIDTH-119)//119是飞机的宽度player.x += speed;}
#endif // 0if (GetAsyncKeyState(VK_SPACE) && Timer(100,1))//{//创建一个子弹createBullet();}}
//产生敌机
void createenemy()
{for (int i = 0; i < ENEMY_NUM; i++){if (!enemy[i].live){enemy[i].live = true;enemy[i].x = rand()%(WIDTH-75);enemy[i].y = 0;enemyHP(i);printf("pos(%d,%d) %d %d\n", enemy[i].x, enemy[i].y, enemy[i].live, enemy[i].hp);break;}}
}//敌机的移动
void enemymove(int speed)
{for (int i = 0; i < ENEMY_NUM; i++){if (enemy[i].live){enemy[i].y += speed;if (enemy[i].y > HIGHT){enemy[i].live = false;}}}
}//开始打飞机
void playplane()
{for (int i = 0; i < ENEMY_NUM; i++){if (!enemy[i].live)continue;for (int k = 0; k < BULLET_NUM; k++){if (!bull[k].live)continue;if (bull[k].x > enemy[i].x && bull[k].x<enemy[i].x + enemy[i].width&& bull[k].y>enemy[i].y && bull[k].y < enemy[i].y + enemy[i].hight)//子弹在飞机的界面内//则代表子弹打住了飞机{bull[k].live = false;enemy[i].hp--;}}if (enemy[i].hp == 0){enemy[i].live = false;}}
}void showenemy()//测试飞机能不能一直往下面落
{for (int i = 0; i < ENEMY_NUM; i++){printf("pos(%d,%d) %d %d\n", enemy[i].x, enemy[i].y,enemy[i].live, enemy[i].hp);}
}int main()
{/*测试
circle(50, 50, 50);//画空心圆
setfillcolor(GREEN);//圆的颜色
fillcircle(100, 100, 50);///实心⚪*///创建图形窗口initgraph(WIDTH, HIGHT,SHOWCONSOLE);//宽长gameinit();//双缓冲绘图BeginBatchDraw();while (1){gameDraw();FlushBatchDraw();playermove(5);Bullmove(5);//防止飞机全部一起出来if (Timer(500,0)){//创建一个飞机createenemy();}if (Timer(20, 2)){enemymove(1);}playplane();}EndBatchDraw();return 0;
}

用VS开发一款“飞机大战“单机游戏<C++>相关推荐

  1. 华为官方解析开源鸿蒙 OpenHarmony 3.1关键特性画布,教你如何完成飞机大战小游戏

    华为技术有限公司的江英杰为大家揭晓了关于开源鸿蒙 OpenHarmony 3.1 Beta 版中的一个关键特性,也就是 ArkUI 开发框架中的 canvas 画布. 据介绍,canvas 是 Ark ...

  2. canvas绘制“飞机大战”小游戏,真香

    canvas是ArkUI开发框架里的画布组件,常用于自定义绘制图形.因为其轻量.灵活.高效等优点,被广泛应用于UI界面开发中. 本期,我们将为大家介绍canvas组件的使用. 目录 一.canvas介 ...

  3. HTML5游戏开发(四):飞机大战之显示场景和元素

    <HTML5游戏开发>系列文章的目的有:一.以最小的成本去入门egret小项目开发,官方的教程一直都是面向中重型:二.egret可以非常轻量:三.egret相比PIXI.js和sprite ...

  4. Vue 开发一个简略版的飞机大战小游戏

    文章目录 使用 Vue 开发一个简略版的飞机大战小游戏 一.实现思路 二.所需知识点 三.实现步骤 使用 Vue 开发一个简略版的飞机大战小游戏 如题,假设你为了向更多访问你博客的人展示你的技术,你决 ...

  5. 飞机大战小游戏(超详细)

    偷学Python之最后的项目二:飞机大战小游戏(超详细) 古之立大事者,不惟有超世之才,亦必有坚忍不拔之志.--苏轼 甜甜先说 这次用Python中的pygame模块来完成一个飞机大战的小游戏:基本思 ...

  6. 飞机大战html游戏全代码js、jquery操作

    飞机大战html游戏全代码 博主的话 运行图片 目录路径 飞机大战.html style.css 进行下一个游戏的开发! 注意事项 博主的话 当时博主只会html,css和原生JavaScript,假 ...

  7. 飞机大战HTML5游戏源码,基于Canvas制作的网页版飞机大战游戏+飞机大战手机端

    简介: 飞机大战HTML5游戏源码是一款基于Canvas制作的网页版飞机大战游戏,画质精美的飞机大战手机端游戏源码 网盘下载地址: http://kekewangLuo.net/W1S2LQcqAT2 ...

  8. 使用小程序制作一个飞机大战小游戏

    此文主要基于微信小程序制作一个飞机大战小游戏,上手即用,操作简单. 一.创建小程序 二.页面实现 三.代码块 一.创建小程序 访问微信公众平台,点击账号注册. 选择小程序,并在表单填写所需的各项信息进 ...

  9. C语言—飞机大战小游戏

    哈工大经典C语言大作业-飞机大战小游戏,源码如下,已经通过编译获得评分19+ (满分20)当时还是太菜了呜呜呜. 可以给大家参考一下,好像本来是加了音乐的,但是你们可能没有对应的音乐MP3文件,所以如 ...

最新文章

  1. 服务器显示接口类型,查看服务器各接口卡情况的命令是:lspci
  2. unity android 启动,Android启动Unity
  3. 《HTML5+CSS3网页设计入门必读》——1.7 使用FTP传输文件
  4. Opera视频出海非洲面临的技术挑战及应对
  5. java 并发线程_Java并发教程–线程之间的可见性
  6. 转义字符的使用和功能python_Python中转义符和格式符的混合使用,python,转义字符,与,格式化...
  7. eclipse启动项目
  8. [转帖]解密微软中间语言MSIL之调试程序(1)
  9. Android使用HttpURLConnection下载图片
  10. php 环信easyui_环信easeui集成:坑总结2018
  11. ViewStub基本用法,include merge
  12. Mac/Win Photoshop CC 2018(V19.0)安装破解激活图文教程(附破解补丁)
  13. CSS 颜色代码大全 CSS颜色对照表
  14. 银行系统数据流图-盒图-软件结构图对应一例
  15. oracle怎么给表建同义词_oracle同义词创建(synonym)
  16. 学了计算机很迷茫怎么办?计算机大三学生怎么找实习工作?
  17. github首次使用提交项目
  18. 安装mysql数据库
  19. 阿里云oss搭建图床以及使用PicGO上传图片到图床
  20. http文件服务器(Ubuntu)

热门文章

  1. 什么是GC Root
  2. Git本地服务器搭建及使用
  3. oracle ora-00911
  4. 凡是函数中未指定存储类型_凡是函数中未指定存储类别的局部变量,其隐含的存储类型是()。...
  5. 阿里不遗余力阻击微信 胜算几何? 转载
  6. 全国首家互联网银行——微众银行内推啦!!!技术产品各个岗位可供选择!!!最后一周!!!抓紧时间啦!!!
  7. 判断数据库或数据库对象是否存在
  8. 【MAPBOX基础功能】29、mapbox地图基础工具 - 获取当前地图层级
  9. Python 使用matplotlib数据可视化显示CSV文件数据
  10. 【转帖】利用wsdl4j解析WSDL文件