河南网站建设定制,网站必须做301重定向吗,手机网站开发还是调用,龙华龙岗网站建设公司[导读]本系列博文内容链接如下#xff1a; 【C】做一个飞机空战小游戏(一)——使用getch()函数获得键盘码值 【C】做一个飞机空战小游戏(二)——利用getch()函数实现键盘控制单个字符移动【C】做一个飞机空战小游戏(三)——getch()函数控制任意造型飞机图标移动 【C】做一个飞… [导读]本系列博文内容链接如下 【C】做一个飞机空战小游戏(一)——使用getch()函数获得键盘码值 【C】做一个飞机空战小游戏(二)——利用getch()函数实现键盘控制单个字符移动【C】做一个飞机空战小游戏(三)——getch()函数控制任意造型飞机图标移动 【C】做一个飞机空战小游戏(四)——给游戏添加背景音乐(多线程技巧应用) 【C】做一个飞机空战小游戏(五)——getch()控制两个飞机图标移动(控制光标位置) 【C】做一个飞机空战小游戏(六)——给两架飞机设置不同颜色(cout输出彩色字符、结构体使用技巧) 【C】做一个飞机空战小游戏(七)——两组按键同时检测平滑移动(GetAsyncKeyState()函数应用) 【C】做一个飞机空战小游戏(八)——生成敌方炮弹(rand()函数应用) 【C】做一个飞机空战小游戏(九)——发射子弹的编程技巧 【C】做一个飞机空战小游戏(十)——子弹击落炮弹、炮弹与飞机相撞 【C】做一个飞机空战小游戏(十一)——游戏过关、通关、结束的设置 本节介绍游戏的过关、通关和游戏结束(game over)的相关设置。过关的依据是敌方死亡炮弹的数量当达到设定数目时即可通过这一关当通过最后一关时即完成通关如果还未通关时所有飞机的命已经没了那游戏就结束了。每一关敌方每波炮弹数量、每关总死亡炮弹数量、炮弹移动速度、炮弹血量、炮弹伤害值都是不一样的是随着关数的增加而递增的也就是游戏过关的难度越来越高。本节还实现了游戏信息显示、爆炸音效、飞机开火音效、控制台窗口大小设置等功能。
目录
一、游戏过关、通关、结束
一过关
1、game结构体新增属性
2、过关的判断条件
3、过关后的游戏属性变化
二通关
1、game结构体新增属性
2、判断条件
3、通关后的游戏属性变化
1主函数、炮弹更新线程、按键更新线程、子弹更新线程
2show_game_complete()函数
三游戏结束
1、game结构体新增属性
2、判断条件
3、游戏结束后的游戏属性变化
1主函数、炮弹更新线程、按键更新线程、子弹更新线程
2show_game_over()函数
二、游戏音效设置
一炸弹爆炸音效
1、爆炸音效线程
2、触发条件
(1)炮弹与飞机相撞
(2)子弹与炮弹相撞
二飞机开火音效
1、开火音效线程
2、触发条件
三、游戏信息显示
一需要显示的信息
1、当前关数
2、剩余炮弹
3、飞机杀敌数目
4、飞机剩余命数
5、飞机复活保护时间
二头文件相关信息
三显示函数
四飞机复活保护程序
1、倒计时线程
2、保护条件
四、漏洞修补
五、控制台窗口设置
一大小设置
二取消最大化最小化
1、函数调用
2、函数定义
六、最终程序
一主函数
二头文件control_plane.h
三库函数control_plane.cpp
七、运行效果
八、不足之处 一、游戏过关、通关、结束
一过关
1、game结构体新增属性
int bombs_round_increase; //下一关敌方每波发射炮弹数量增加值
int bombs_stage_increase; //下一关总计发射炮弹数量增加值
int bomb_interval_reduce //下一关炮弹更新间隔减少值
int last_stage; //游戏一共多少关2、过关的判断条件
当前已发射并死亡的炮弹数量game.cur_num_bomb当前关总计发射并死亡的炮弹数量game.bombs_stage并且当前关不是最后一关如果当前关是最后一关就是通关。
3、过关后的游戏属性变化
敌方每波炮弹数量、每关总死亡炮弹数量、炮弹移动速度、炮弹血量、炮弹伤害值都相应增加。代码如下
if(game.cur_num_bombgame.bombs_stage)
{if(game.cur_stagegame.last_stage){game.cleartrue;game.cur_num_bomb0;game.bombs_stagegame.bombs_stage_increase;game.bombs_roundgame.bombs_round_increase;game.bomb_interval-game.bomb_interval_reduce;game.cur_stage1;init_bombs();init_bullets(); }else{game.completetrue;}
}
炮弹血量、伤害值的变化在init_bombs()函数中
//单个炮弹初始化函数
Bomb init_bomb(Bomb bomb,int stage)
{bomb.location.xrand()%r_b; //x坐标随机 bomb.location.yb_b6; //y显示区域底部下一行 bomb.iconicon_bomb; //设置炮弹图标 bomb.color6; //设置炮弹颜色为6黄色 bomb.dam1stage/3; //炮弹伤害值每过3关增加1点 bomb.hpstage; //炮弹血量每过1关增加1点 bomb.alivefalse; //炮弹设置为存活状态 bomb.rtrand()%(eq_rt1)1; //炮弹复活时间随机生成 return bomb;
}//所有炮弹初始化函数
void init_bombs(void)
{game.bomb_movefalse; for(int i0;igame.bombs_round;i){bomb[i]init_bomb(bomb[i],game.cur_stage); }
}
二通关
1、game结构体新增属性
bool show_complete; //是否显示游戏通关信息
2、判断条件
判定条件见过关的判定条件。
3、通关后的游戏属性变化
通关后game.completetrue然后要显示通关信息。
1主函数、炮弹更新线程、按键更新线程、子弹更新线程
while(game.complete)
{show_game_complete();
}
2show_game_complete()函数
//显示游戏通关信息
void show_game_complete(void)
{if(!game.show_complete){game.show_completetrue;Sleep(100); system(cls);show_info();gotoxy((l_br_b)/2-4,(t_bb_b)/2); ColorCout(game_complete_text,game.info_color); }
}
三游戏结束
1、game结构体新增属性
bool show_gameover; //是否显示游戏结束信息
2、判断条件
判断条件就是两架飞机命都为0具体代码在void* thread_bomb(void* arg)线程中
//以下一段程序作用:判断两架飞机都没有命的情况即为游戏结束
if(!(plane[0].life0||plane[1].life0))
{game.gameovertrue;
}
3、游戏结束后的游戏属性变化
游戏结束后要显示游戏结束的信息。
1主函数、炮弹更新线程、按键更新线程、子弹更新线程
while(game.gameover) //等待游戏结束
{show_game_over();
}
2show_game_over()函数
//显示游戏结束信息
void show_game_over(void)
{ if(!game.show_gameover){game.show_gameovertrue;Sleep(100); system(cls);show_info();gotoxy((l_br_b)/2-4,(t_bb_b)/2); ColorCout(game_over_text,game.info_color); }
}
二、游戏音效设置
一炸弹爆炸音效
1、爆炸音效线程
//********************************************************************************//以下三个函数为播放爆炸音效功能
//********************************************************************************
//循环播放爆炸音乐线程函数
void* thread_bomb_music(void* arg) //
{ while(1){ if(game.bomb){play_bomb_music();game.bombfalse; } }
} //创建爆炸音效播放线程,开始循环播放音效
void bomb_music()
{pthread_t tid; pthread_create(tid, NULL, thread_bomb_music, NULL);
}//播放一遍爆炸音效 void play_bomb_music() { mciSendString(TEXT(open bomb.mp3 alias s1),NULL,0,NULL);mciSendString(TEXT(play s1),NULL,0,NULL);Sleep(2*1000);//2*1000意思是2秒,是整首音乐的时长 mciSendString(TEXT(close S1),NULL,0,NULL);
}
2、触发条件
(1)炮弹与飞机相撞
代码在thread_bomb(void* arg)线程中
if(collide(plane[j],bomb[i])) //判断飞机是否与炮弹相撞
{game.bombtrue;......
}
(2)子弹与炮弹相撞
代码在thread_bullet(void* arg)线程中
if(shoot(bullet[i][j],bomb[k])) //如果被击中
{game.bombtrue; //爆炸声音启动...... }
二飞机开火音效
1、开火音效线程
//********************************************************************************//以下三个函数为播放机开火音效功能
//********************************************************************************
//循环播放飞机开火音效线程函数
void* thread_fire_music(void* arg) //
{ while(1){ if(game.fire){play_fire_music();game.firefalse; } }
} //创建飞机开火音效播放线程,开始循环播放音乐
void fire_music()
{pthread_t tid; pthread_create(tid, NULL, thread_fire_music, NULL);
}//播放一遍飞机开火音效 void play_fire_music() { mciSendString(TEXT(open fire.mp3 alias s1),NULL,0,NULL);mciSendString(TEXT(play s1),NULL,0,NULL);Sleep(1500);//153*1000意思是153秒,是整首音乐的时长 mciSendString(TEXT(close S1),NULL,0,NULL);
}
2、触发条件
飞机开火键按下代码在开火函数中
//发射子弹
Bullet fire(Plane plane,Bullet bullet)
{ game.firetrue; ......
}
三、游戏信息显示
一需要显示的信息
1、当前关数
当前所在关的关数game.cur_stage。
2、剩余炮弹
剩余炮弹该关设定总死亡炮弹数量-当前已死亡炮弹数量。
game.bombs_stage-game.cur_num_bomb。
3、飞机杀敌数目
飞机杀敌数目该飞机子弹击落炮弹数量飞机撞落炮弹数量。
4、飞机剩余命数
飞机剩余命数plane.life
5、飞机复活保护时间
防止飞机刚复活时其初始化位置刚好有炮弹而将飞机撞落所以设定了复活保护时间为10s。在此期间炮弹与飞机相撞飞机和炮弹都不会掉血。
二头文件相关信息
//以下为游戏当中要显示的信息文本
#define cur_stage_text 当前关次
#define remain_bombs_text 剩余炮弹
#define play0_kill_text 飞机0杀敌
#define play1_kill_text 飞机1杀敌
#define play0_life_text 飞机0命数
#define play1_life_text 飞机1命数
#define play0_rt_text 飞机0保护时间
#define play1_rt_text 飞机1保护时间
#define game_complete_text 恭喜游戏通关
#define game_over_text 遗憾游戏结束extern Location loc_info;
三显示函数
//显示游戏信息
void show_info(void)
{gotoxy(loc_info.x,loc_info.y);ColorCout(cur_stage_text,game.info_color);ColorCout(game.cur_stage,game.info_color);gotoxy(loc_info.x,loc_info.y2);ColorCout(remain_bombs_text,game.info_color);ColorCout(game.bombs_stage-game.cur_num_bomb,game.info_color);gotoxy(loc_info.x,loc_info.y10);ColorCout(play0_kill_text,plane[0].color);ColorCout(plane[0].kill,game.info_color);gotoxy(loc_info.x,loc_info.y12);ColorCout(play1_kill_text,plane[1].color);ColorCout(plane[1].kill,game.info_color);gotoxy(loc_info.x,loc_info.y20);ColorCout(play0_life_text,plane[0].color);ColorCout(plane[0].life,game.info_color);gotoxy(loc_info.x,loc_info.y22);ColorCout(play1_life_text,plane[1].color);ColorCout(plane[1].life,game.info_color);gotoxy(loc_info.x,loc_info.y30);ColorCout(play0_rt_text,plane[0].color);ColorCout(plane[0].rt,game.info_color);gotoxy(loc_info.x,loc_info.y32);ColorCout(play1_rt_text,plane[1].color);ColorCout(plane[1].rt,game.info_color);
}
四飞机复活保护程序
1、倒计时线程
//********************************************************************************//以下两个函数为飞机复活时间计时功能
//********************************************************************************
//飞机复活保护时间线程
void* thread_plane_rt(void* arg) //
{ while(1){ Sleep(1000); for(int j0;jgame.num_plane;j){if(plane[j].rt0){plane[j].rt-1;}}}
} //创建飞机复活保护时间线程
void plane_rt()
{pthread_t tid; pthread_create(tid, NULL, thread_plane_rt, NULL);
}
2、保护条件
在炮弹位置更新线程中判断飞机与炮弹相撞之前先要判断飞机是否存活并且不在保护期内。
if(plane[j].alive!plane[j].rt) //判断的必要条件为飞机存活并且已经出了死亡恢复保护期
{if(collide(plane[j],bomb[i])) //判断飞机是否与炮弹相撞 {......}
}
四、漏洞修补
游戏增加了如果两架飞机至少有一架飞机还有命的情况下飞机在死亡状态必须复活。因为游戏在两架飞机在有命而不复活的情况下还继续进行而每关设定的炮弹死亡也包括冲出底部边界情况(此种情况称为坠落)那样就可以不复活而让炮弹只通过坠落就可以实现通关了。
//以下一段程序作用:防止两架飞机都死亡之后且至少有一架飞机还有命的情况下不按复活键让游戏在无飞机的情况下过关
if(!plane[(j1)%2].alive) //(j1)%2即为除j之外的一架飞机j0(j1)%21j1(j1)%20
{if(plane[(j1)%2].life0) //判断另一架飞机是否还有命如果有则将其复活如果没有则将自己复活 {plane[(j1)%2]init_plane(plane[(j1)%2]);show_plane(plane[(j1)%2]); }else{if(plane[j].life0){plane[j]init_plane(plane[j]);show_plane(plane[j]); }}}
五、控制台窗口设置
对控制台窗口的设置都在初始化函数void init(void)中。
一大小设置
system(mode con cols175 lines46); //设置控制台屏幕的大小
二取消最大化最小化
1、函数调用
SizeGoAway();
2、函数定义
//取消最大化最小化
void SizeGoAway() {SetWindowLongPtrA(GetConsoleWindow(),GWL_STYLE,GetWindowLongPtrA(GetConsoleWindow(), GWL_STYLE) ~WS_SIZEBOX ~WS_MAXIMIZEBOX ~WS_MINIMIZEBOX);
}六、最终程序
一主函数
#include control_plane.h
#include quenue.h
#include graphics.h
#include sstream
//#include acllib.h
using namespace std; Plane plane[eq_plane];
Game game;
Bomb bomb[eq_bombs_round];
Bullet bullet[eq_plane][eq_bullets_round];
Location plocation[]{{2*r_b/3,b_b},{r_b/3,b_b}};Location loc_info{r_b15,t_b5};int main(int argc, char** argv) { init(); //初始化 bgmusic();//播放背景音乐bomb_music(); fire_music();getmykey();//循环等待键盘指令bomb_location_update(); bullet_location_update();plane_rt();while(1) {while(game.pause){;}while(game.complete){show_game_complete();}while(game.gameover){show_game_over();}if(plane[0].keycmd!none_cmd ||plane[1].keycmd!none_cmd ||game.bomb_move ||game.bullet_move){game.bomb_movefalse;game.bullet_movefalse;system(cls); show_info();for(int i0;igame.num_plane;i){if(plane[i].alive){show_plane(plane[i]);//刷新飞机图标}}for(int i0;ieq_plane;i){for(int j0;jeq_bullets_round;j){ if(bullet[i][j].alive){show_bullet(bullet[i][j]);}} } for(int i0;igame.bombs_round;i){if(bomb[i].alive){show_bomb(bomb[i]);}}} }return 0;
}
二头文件control_plane.h
#ifndef CONTROL_PLANE_H
#define CONTROL_PLANE
#include iostream
#include ctime
#include string
#includestdlib.h
#includewindows.h
#include pthread.h//导入线程头文件库
#include mmsystem.h //导入声音头文件库
#pragma comment(lib,winmm.lib)//导入声音的链接库
#define _CRT_SECURE_NO_WARNINGS
using namespace std;#define t_b 0 //图形显示区域上侧边界
#define l_b 0 //图形显示区域左侧边界
#define r_b 140 //图形显示区域右侧边界
#define b_b 40 //图形显示区域下侧边界
#define plane_width 9 //飞机宽度
#define plane_height 6 //飞机高度 #define eq_plane 2 //飞机架数
#define eq_bombs_round 32 //eqend quantity最后一关每波炮弹数量
#define eq_rt 5 //炮弹复活最大时间
#define eq_bullets_round 40 //eqend quantity飞机每波发射子弹最大数量 //以下为游戏当中要显示的信息文本
#define cur_stage_text 当前关次
#define remain_bombs_text 剩余炮弹
#define play0_kill_text 飞机0杀敌
#define play1_kill_text 飞机1杀敌
#define play0_life_text 飞机0命数
#define play1_life_text 飞机1命数
#define play0_rt_text 飞机0保护时间
#define play1_rt_text 飞机1保护时间
#define game_complete_text 恭喜游戏通关
#define game_over_text 遗憾游戏结束//定义飞机造型
const string icon_plane1[]{ ■,■ ■ ■,■■■■■,■ ■ ■, ■, ■■■};
const string icon_plane2[]{ ■,■ ■ ■,■■■■■, ■, ■■■,■■■■■};//定义炮弹造型
const string icon_bomb■;//定义子弹造型
const string icon_bullet■;//定义坐标结构体
typedef struct{int x;int y;
} Location;//定义移动方向命令枚举类型
typedef enum {none_cmd,up_cmd,down_cmd,left_cmd,right_cmd} direction_cmd; //定义游戏结构体
typedef struct{int cur_stage; //游戏当前关 int bombs_round; //当前关敌方每波发射炮弹数量int bombs_round_increase; //下一关敌方每波发射炮弹数量增加值 int bombs_stage; //当前关总计发射炮弹数量int bombs_stage_increase; //下一关总计发射炮弹数量增加值bool clear; //游戏过关 bool complete; //游戏通关 bool gameover; //游戏结束int num_plane; //飞机数量 int cur_num_bomb; //当前已发射炮弹数量 int bomb_interval; //炮弹位置更新间隔int bomb_interval_reduce; //下一关炮弹位置更新间隔减少值 int bullet_interval; //子弹位置更新间隔 bool bomb_move; //炮弹是否移动bool bullet_move; //子弹是否移动bool pause; //游戏是否暂停int last_stage; //游戏最后一关数目 int info_color; //游戏信息文本颜色 bool bomb; //是否调用爆炸音效 bool fire; //是否调用开火音效 bool show_gameover; //是否显示游戏结束信息 bool show_complete; //是否显示游戏通关信息
}Game;//定义飞机结构体
typedef struct{Location location; //飞机坐标 int color; //飞机颜色 int icon; //飞机图标编号 direction_cmd keycmd; //飞机移动方向命令 bool fire; //飞机是否开火 int cnt_bullets; //按一次开火键加1然后初始化bullet[cnt_bullets],子弹死亡一个减1int hp; //飞机血量 bool alive; //飞机存活标志 int No; //飞机序号 int life; //飞机命数int kill; //飞机击落炮弹数量int rt; //rtrespawn time复活时间在此期间炮弹对飞机无伤害
}Plane;//定义敌方炮弹结构体
typedef struct{Location location; //炮弹位置 bool alive; //炮弹是否存活 int color; //炮弹颜色string icon; //炮弹图标int rt; //rtrespawn time复活时间 int hp; //hphit point 生命值此值0时敌方炮弹死亡敌方炮弹被飞机子弹击中hp会减少坠地或与飞机相撞hp直接降为0 int dam; //damdamage 伤害值int type; //炮弹类型
}Bomb;//定义子弹结构体
typedef struct{Location location; //子弹位置 bool alive; //子弹是否存活 int color; //子弹颜色string icon; //子弹图标 int hp; //hphit point 生命值子弹击中炮弹或冲出屏幕上方hp直接降为0子弹死亡 int dam; //damdamage 伤害值int type; //子弹类型
}Bullet;extern Plane plane[eq_plane];
extern Game game;
extern Bomb bomb[eq_bombs_round];
extern Bullet bullet[eq_plane][eq_bullets_round];extern Location plocation[];
extern Location loc_info;//声明刷新飞机位置函数
void show_plane(Plane plane);//获取键盘指令
void key(void);//更新所有飞机坐标
void plane_location_update(void);//初始化函数
void init(void);//播放背景音乐线程
void* thread_bgmusic(void* arg);
void play_bgmusic();
void bgmusic();//获取按键指令线程
void* thread_key(void* arg);
void getmykey();//输出彩色字符函数
templatetypename T //T表示任何可以被cout输出的类型
void ColorCout(T t, const int ForeColor 7, const int BackColor 0);void gotoxy(int x, int y);void init_bombs(void);
Bomb init_(Bomb bomb,int stage);
void* thread_bomb(void* arg);
void bomb_location_update();
void show_bomb(Bomb bomb);void bullet_location_update(); //子弹位置更新
void* thread_bullet(void* arg); //子弹线程函数
Bullet init_bullet(Bullet bullet); //单个子弹初始化
void init_bullets(void); //所有子弹初始化
Bullet fire(Plane plane,Bullet bullet); //飞机开火函数确定子弹出现的起始位置
void show_bullet(Bullet bullet); //显示子弹图标 bool collide(Plane plane,Bomb bomb);
bool shoot(Bullet bullet,Bomb bomb);Plane init_plane(Plane plane);
void init_planes(void);void* thread_bomb_music(void* arg);
void bomb_music();
void play_bomb_music();void* thread_fire_music(void* arg);
void fire_music();
void play_fire_music();void show_info(void);
void show_game_complete(void);
void show_game_over(void);void plane_rt();
void* thread_plane_rt(void* arg);void SizeGoAway();#endif
三库函数control_plane.cpp
#include iostream
#include conio.h
#include string
#include control_plane.h
#includewindows.h
using namespace std;//彩色输出函数
templatetypename T //T表示任何可以被cout输出的类型
void ColorCout(T t, const int ForeColor 7, const int BackColor 0)
{// 0 黑色 1 蓝色 2 绿色 3 浅绿色 4 红色 5 紫色 6 黄色 7 白色// 8 灰色 9 淡蓝色 10 淡绿色 11 淡浅绿色 12 淡红色 13 淡紫色 14 淡黄色 15 亮白色SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), ForeColor BackColor * 0x10);cout t;SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
}//隐藏光标函数
HANDLE han GetStdHandle(-11);
void hide(){CONSOLE_CURSOR_INFO cursor;cursor.bVisible 0;cursor.dwSize 1;SetConsoleCursorInfo(han,cursor);
}//光标移动位置
void gotoxy(int x, int y) {COORD pos { x,y };HANDLE hOut GetStdHandle(STD_OUTPUT_HANDLE);//获取标准输出设备句柄SetConsoleCursorPosition(hOut, pos);//两个参数分别指定哪个窗口具体位置
}//初始化函数
void init(void)
{plane[0].No0; //飞机0序号为0 plane[1].No1; //飞机1序号为1plane[0].life3; //飞机0命数为3 plane[1].life3; //飞机1命数为3plane[0].kill0; //飞机0初始杀敌数为0 plane[1].kill0; //飞机1初始杀敌数为0 srand(time(NULL)); //设置随机函数种子 game.num_plane2; //飞机数量 game.bombs_round5; //第一关炮弹数量置5 game.bomb_movefalse; //炮弹是否移动标志置否 game.bullet_movefalse; //子弹是否移动标志置否 game.bomb_interval1000; //炮弹初始移动间隔1秒钟 game.cur_stage1; //游戏初始关设置为1 game.bombs_stage10; //游戏初始关炮弹总数设置为10 game.pausefalse; //游戏暂停设置为否 game.info_color5; //游戏信息颜色设置为5紫色 game.cur_num_bomb0; //游戏当前死亡炮弹数量设置为0 game.bullet_interval500; //子弹移动间隔设置为1秒钟game.bombfalse; //爆炸标志设置为否此标志为爆炸声音播放标志 game.firefalse; //飞机开火标志此标志为飞机开火声音播放标志 game.gameoverfalse; //游戏结束标志设置为否 game.completefalse; //游戏通关标志设置为否game.last_stage10; //游戏总关数设置为10game.bombs_round_increase3;//每过一关敌方每波发射炮弹数量增加3个 game.bombs_stage_increase10;//每过一关敌方该关总发射炮弹数量增加10个game.bomb_interval_reduce100; game.show_gameoverfalse; //显示游戏结束信息标志设置为否game.show_completefalse; //显示游戏通关信息标志设置为否 system(mode con cols175 lines46); //设置控制台屏幕的大小SizeGoAway(); //取消控制台屏幕的最大化最小化 init_bombs(); //初始化所有炸弹 init_bullets(); //初始化所有子弹 init_planes(); //初始化所有飞机 system(cls);for(int i0;igame.num_plane;i)//刷新飞机图标{ show_plane(plane[i]);} hide();//隐藏光标
}//********************************************************************************//以下三个函数为获得按键指令线程函数
//********************************************************************************
void* thread_key(void* arg)
{while(1){Sleep(60); //获取指令延时一定时间起滤波作用延缓获取指令的响应速度 key(); //获取按键指令plane_location_update() ;//获取完指令马上更新飞机坐标 }
}//按键指令线程启动函数
void getmykey()
{pthread_t tid; pthread_create(tid, NULL, thread_key, NULL);
}//获取键盘指令函数
void key(void)
{if (GetAsyncKeyState(VK_SPACE) 0x8000){Sleep(50);game.pause!game.pause; }while(game.complete){show_game_complete();}while(game.gameover){show_game_over();}if(!game.pause){if(plane[0].alive){direction_cmd cnone_cmd;if (GetAsyncKeyState(VK_UP) 0x8000) c up_cmd;if (GetAsyncKeyState(VK_DOWN) 0x8000) c down_cmd;if (GetAsyncKeyState(VK_LEFT) 0x8000) c left_cmd;if (GetAsyncKeyState(VK_RIGHT) 0x8000) c right_cmd;plane[0].keycmdc; //刷新飞机方向指令 if (GetAsyncKeyState(P) 0x8000) plane[0].fire true; //飞机开火指令}else{if(plane[0].life0){if (GetAsyncKeyState(O) 0x8000) //飞机复活指令{plane[0]init_plane(plane[0]);show_plane(plane[0]);}}}if(plane[1].alive){direction_cmd dnone_cmd;if (GetAsyncKeyState(W) 0x8000) d up_cmd;if (GetAsyncKeyState(S) 0x8000) d down_cmd;if (GetAsyncKeyState(A) 0x8000) d left_cmd;if (GetAsyncKeyState(D) 0x8000) d right_cmd;plane[1].keycmdd;//刷新飞机图标if (GetAsyncKeyState(F) 0x8000) plane[1].fire true;}else{if(plane[1].life0){if (GetAsyncKeyState(Q) 0x8000){plane[1]init_plane(plane[1]);show_plane(plane[1]);}} } }
}//飞机图标刷新函数
void show_plane(Plane plane) //预先定义字符定位显示函数x是列坐标y是行坐标原点(x0,y0)位于屏幕左上角
{int x,y;int i,j;int rows;xplane.location.x;yplane.location.y;switch(plane.icon){case 1://第一种造型 rowssizeof(icon_plane1)/sizeof(icon_plane1[0]);for(i0;irows;i) {gotoxy(x,yi); ColorCout(icon_plane1[i],plane.color);}break;case 2://第二种造型 rowssizeof(icon_plane2)/sizeof(icon_plane2[0]);for(i0;irows;i) {gotoxy(x,yi); ColorCout(icon_plane2[i],plane.color);}break; }
}//更新两个飞机的坐标
void plane_location_update(void)
{ for(int i0;i2;i){if(plane[i].keycmd!none_cmd) {int x,y;xplane[i].location.x;yplane[i].location.y;switch(plane[i].keycmd){case up_cmd:y--; //字符上移一行行值y减1if(yt_b) //限定y值最小值为0{yt_b;}break;case down_cmd:y; //字符下移一行行值y加1if(yb_b) //限定y高度 {yb_b;}break;case left_cmd:x--; //字符左移一列列值x减1if(xl_b){xl_b; //限定x最小值为0; }break;case right_cmd:x; //字符右移一列列值x加1if(xr_b){xr_b; //限定x宽度}break;}plane[i].location.xx;plane[i].location.yy;plane[i].keycmdnone_cmd; }}
}//单个炮弹初始化函数
Bomb init_bomb(Bomb bomb,int stage)
{bomb.location.xrand()%r_b; //x坐标随机 bomb.location.yb_b6; //y显示区域底部下一行 bomb.iconicon_bomb; //设置炮弹图标 bomb.color6; //设置炮弹颜色为6黄色 bomb.dam1stage/3; //炮弹伤害值每过3关增加1点 bomb.hpstage; //炮弹血量每过1关增加1点 bomb.alivefalse; //炮弹设置为存活状态 bomb.rtrand()%(eq_rt1)1; //炮弹复活时间随机生成 return bomb;
}//所有炮弹初始化函数
void init_bombs(void)
{game.bomb_movefalse; for(int i0;igame.bombs_round;i){bomb[i]init_bomb(bomb[i],game.cur_stage); }
}//炮弹位置更新 线程
void* thread_bomb(void* arg)
{while(1){Sleep(game.bomb_interval); //更新间隔 game.bomb_movetrue; //更新一次炮弹移动一次 while(game.pause) //等待游戏暂停 {;}while(game.complete) //等待游戏通关 {show_game_complete();}while(game.gameover) //等待游戏结束 {show_game_over();}//依次查询炮弹状态、更新位置查询炮弹是否死亡记录炮弹死亡数目计算是否过关是否通关。//还查询炮弹是否与飞机相撞计算飞机血量死亡状态飞机命数游戏是否gameover。 for(int i0;igame.bombs_round;i){ if(bomb[i].alive) //如果炮弹存活则进行移动如果死亡则进行复活前的计时准备复活 {bomb[i].location.y; //炮弹移动一步 if(bomb[i].location.yb_b5) //查询炮弹是否冲出底部边界 {bomb[i].hp0; }//此循环用于查询炮弹是否与飞机相撞 for(int j0;jgame.num_plane;j){if(plane[j].alive!plane[j].rt) //判断的必要条件为飞机存活并且已经出了死亡恢复保护期 {if(collide(plane[j],bomb[i])) //判断飞机是否与炮弹相撞 {game.bombtrue; //爆炸声音启动 bomb[i].hp0; //炸弹血量置0 plane[j].hp-bomb[i].dam; //飞机血量减少值为炮弹伤害值 plane[j].kill1; //飞机杀敌数加1 if(plane[j].hp0) //判断飞机血量是否降到0以下 {plane[j].alivefalse; //飞机死亡 plane[j].life-1; //飞机命数减1 plane[j].keycmdnone_cmd; //飞机移动指令置空 plane[j].location.x0; //飞机x坐标置0 plane[j].location.yb_b8; //飞机y坐标置底部边界下3行 //以下一段程序作用:防止两架飞机都死亡之后且至少有一架飞机还有命的情况下不按复活键让游戏在无飞机的情况下过关 if(!plane[(j1)%2].alive) //(j1)%2即为除j之外的一架飞机j0(j1)%21j1(j1)%20 {if(plane[(j1)%2].life0) //判断另一架飞机是否还有命如果有则将其复活如果没有则将自己复活 {plane[(j1)%2]init_plane(plane[(j1)%2]);show_plane(plane[(j1)%2]); }else{if(plane[j].life0){plane[j]init_plane(plane[j]);show_plane(plane[j]); }}}//以下一段程序作用:判断两架飞机都没有命的情况即为游戏结束 if(!(plane[0].life0||plane[1].life0)){game.gameovertrue;} } }}} if(bomb[i].hp0){bomb[i]init_bomb(bomb[i],game.cur_stage);game.cur_num_bomb;if(game.cur_num_bombgame.bombs_stage) {if(game.cur_stagegame.last_stage){game.cleartrue;game.cur_num_bomb0;game.bombs_stagegame.bombs_stage_increase;game.bombs_roundgame.bombs_round_increase;game.bomb_interval-game.bomb_interval_reduce;game.cur_stage1;init_bombs();init_bullets();}else{game.completetrue;} } } }else //复活前的倒计时 {bomb[i].rt--;if(bomb[i].rt0) //倒计时结束 {bomb[i].alivetrue; //复活 bomb[i].location.yt_b; //将炮弹移动到界面顶部 } }} }
}//启动炮弹位置更新线程
void bomb_location_update()
{pthread_t tid; pthread_create(tid, NULL, thread_bomb, NULL);
}炮弹图标刷新函数
void show_bomb(Bomb bomb) //预先定义字符定位显示函数x是列坐标y是行坐标原点(x0,y0)位于屏幕左上角
{int x,y; xbomb.location.x;ybomb.location.y;hide();//隐藏光标gotoxy(x,y);ColorCout(bomb.icon,bomb.color);} //发射子弹
Bullet fire(Plane plane,Bullet bullet)
{game.bullet_movetrue;game.firetrue;bullet.location.xplane.location.xplane_width/2; bullet.location.yplane.location.y-1;bullet.alivetrue; return bullet;
}//单个子弹初始化函数
Bullet init_bullet(Bullet bullet)
{bullet.iconicon_bullet;bullet.location.x0;bullet.location.yb_b7;bullet.alivefalse;bullet.color4;bullet.dam1;bullet.hp1; return bullet;
}//所有子弹初始化函数
void init_bullets(void)
{game.bullet_movefalse; for(int i0;ieq_plane;i){for(int j0;jeq_bullets_round;j){bullet[i][j]init_bullet(bullet[i][j]); } }
}//单个飞机初始化函数
Plane init_plane(Plane plane)
{plane.alivetrue; plane.hp3; plane.keycmdnone_cmd;plane.locationplocation[plane.No];plane.colorplane.No1;plane.iconplane.No1;plane.rt10; return plane;
}//所有飞机初始化函数
void init_planes(void)
{for(int i0;igame.num_plane;i)//刷新飞机图标{ plane[i]init_plane(plane[i]);}
}//子弹位置更新 线程
void* thread_bullet(void* arg)
{while(1){while(game.pause) //等待游戏暂停指令 {;}while(game.complete) //等待游戏通关 {show_game_complete();}while(game.gameover) //等待游戏结束{show_game_over();}Sleep(game.bullet_interval);//子弹位置更新间隔 for(int i0;ieq_plane;i){if(plane[i].fire) //如果飞机开火要搜寻一个子弹处于死亡状态的位置激活子弹 { game.bullet_movetrue; for(int j0;jeq_bullets_round;j){if(!bullet[i][j].alive){bullet[i][j]fire(plane[i],bullet[i][j]);break;} }}plane[i].firefalse; //飞机开火完成后开火指令置0 }for(int i0;ieq_plane;i) //判断是哪架飞机发出的子弹与炮弹相撞 {for(int j0;jeq_bullets_round;j) //判断是哪个位置的子弹{ if(bullet[i][j].alive) //判断条件为子弹处于激活状态 {bullet[i][j].location.y--; //子弹向上移动一行 if(bullet[i][j].location.yt_b) //子弹冲出顶部边界 {bullet[i][j].hp0; }//此循环用于查询炮弹是否被子弹击中for(int k0;kgame.bombs_round;k) { if(shoot(bullet[i][j],bomb[k])) //如果被击中 {game.bombtrue; //爆炸声音启动 bomb[k].hp-bullet[i][j].dam; //炮弹血量减少值为子弹伤害值 bullet[i][j].hp-bomb[k].dam; //子弹血量减少值为炮弹伤害值 if(bomb[k].hp0) //判断炮弹是否被击落 {plane[i].kill1; //记录击落炮弹的飞机该飞机杀敌数加1 }}}//如果子弹血量值降到0以下则子弹初始化等待下次被激活 if(bullet[i][j].hp0) {bullet[i][j]init_bullet(bullet[i][j]); } }} } }
}//子弹位置更新
void bullet_location_update()
{pthread_t tid; pthread_create(tid, NULL, thread_bullet, NULL);
}子弹图标刷新函数
void show_bullet(Bullet bullet) //预先定义字符定位显示函数x是列坐标y是行坐标原点(x0,y0)位于屏幕左上角
{int x,y; xbullet.location.x;ybullet.location.y;hide();//隐藏光标gotoxy(x,y);ColorCout(bullet.icon,bullet.color);
} //********************************************************************************//以下函数功能判断炮弹是否被飞机撞击
//********************************************************************************bool collide(Plane plane,Bomb bomb)
{bool cpb,cx0,cx1,cy0,cy1;cx0bomb.location.xplane.location.x-1;cx1bomb.location.xplane.location.xplane_width;cy0bomb.location.yplane.location.y;cy1bomb.location.yplane.location.yplane_height; cpbcx0 cx1 cy0 cy1;return cpb;
}//********************************************************************************//以下函数功能判断炮弹是否被子弹击中
//********************************************************************************bool shoot(Bullet bullet,Bomb bomb)
{bool sbb,sx0,sx1,sy0,sy1;sx0(bomb.location.xbullet.location.x-1);sx1(bomb.location.xbullet.location.x1); sy0(bomb.location.ybullet.location.y-1);sy1(bomb.location.ybullet.location.y1); sbbsx0 sx1sy0sy1;return sbb;
}//********************************************************************************//以下三个函数为播放背景音乐功能
//********************************************************************************//播放一遍背景音乐 void play_bgmusic() { mciSendString(TEXT(open hero.mp3 alias s1),NULL,0,NULL);mciSendString(TEXT(play s1),NULL,0,NULL);Sleep(153*1000);//153*1000意思是153秒,是整首音乐的时长 mciSendString(TEXT(close S1),NULL,0,NULL); }//循环播放音乐线程函数
void* thread_bgmusic(void* arg) //
{ while(1){ play_bgmusic();}
} //创建音乐播放线程,开始循环播放音乐
void bgmusic()
{pthread_t tid; pthread_create(tid, NULL, thread_bgmusic, NULL);
}//********************************************************************************//以下三个函数为播放爆炸音效功能
//********************************************************************************
//循环播放爆炸音乐线程函数
void* thread_bomb_music(void* arg) //
{ while(1){ if(game.bomb){play_bomb_music();game.bombfalse; } }
} //创建爆炸音效播放线程,开始循环播放音效
void bomb_music()
{pthread_t tid; pthread_create(tid, NULL, thread_bomb_music, NULL);
}//播放一遍爆炸音效 void play_bomb_music() { mciSendString(TEXT(open bomb.mp3 alias s1),NULL,0,NULL);mciSendString(TEXT(play s1),NULL,0,NULL);Sleep(2*1000);//2*1000意思是2秒,是整首音乐的时长 mciSendString(TEXT(close S1),NULL,0,NULL);
}//********************************************************************************//以下三个函数为播放机开火音效功能
//********************************************************************************
//循环播放飞机开火音效线程函数
void* thread_fire_music(void* arg) //
{ while(1){ if(game.fire){play_fire_music();game.firefalse; } }
} //创建飞机开火音效播放线程,开始循环播放音乐
void fire_music()
{pthread_t tid; pthread_create(tid, NULL, thread_fire_music, NULL);
}//播放一遍飞机开火音效 void play_fire_music() { mciSendString(TEXT(open fire.mp3 alias s1),NULL,0,NULL);mciSendString(TEXT(play s1),NULL,0,NULL);Sleep(1500);//153*1000意思是153秒,是整首音乐的时长 mciSendString(TEXT(close S1),NULL,0,NULL);
}//显示游戏信息
void show_info(void)
{gotoxy(loc_info.x,loc_info.y);ColorCout(cur_stage_text,game.info_color);ColorCout(game.cur_stage,game.info_color);gotoxy(loc_info.x,loc_info.y2);ColorCout(remain_bombs_text,game.info_color);ColorCout(game.bombs_stage-game.cur_num_bomb,game.info_color);gotoxy(loc_info.x,loc_info.y10);ColorCout(play0_kill_text,plane[0].color);ColorCout(plane[0].kill,game.info_color);gotoxy(loc_info.x,loc_info.y12);ColorCout(play1_kill_text,plane[1].color);ColorCout(plane[1].kill,game.info_color);gotoxy(loc_info.x,loc_info.y20);ColorCout(play0_life_text,plane[0].color);ColorCout(plane[0].life,game.info_color);gotoxy(loc_info.x,loc_info.y22);ColorCout(play1_life_text,plane[1].color);ColorCout(plane[1].life,game.info_color);gotoxy(loc_info.x,loc_info.y30);ColorCout(play0_rt_text,plane[0].color);ColorCout(plane[0].rt,game.info_color);gotoxy(loc_info.x,loc_info.y32);ColorCout(play1_rt_text,plane[1].color);ColorCout(plane[1].rt,game.info_color);
}//显示游戏通关信息
void show_game_complete(void)
{if(!game.show_complete){game.show_completetrue;Sleep(100); system(cls);show_info();gotoxy((l_br_b)/2-4,(t_bb_b)/2); ColorCout(game_complete_text,game.info_color); }
}//显示游戏结束信息
void show_game_over(void)
{ if(!game.show_gameover){game.show_gameovertrue;Sleep(100); system(cls);show_info();gotoxy((l_br_b)/2-4,(t_bb_b)/2); ColorCout(game_over_text,game.info_color); }
}//********************************************************************************//以下两个函数为飞机复活时间计时功能
//********************************************************************************
//飞机复活保护时间线程
void* thread_plane_rt(void* arg) //
{ while(1){ Sleep(1000); for(int j0;jgame.num_plane;j){if(plane[j].rt0){plane[j].rt-1;}}}
} //创建飞机复活保护时间线程
void plane_rt()
{pthread_t tid; pthread_create(tid, NULL, thread_plane_rt, NULL);
}//取消最大化最小化
void SizeGoAway() {SetWindowLongPtrA(GetConsoleWindow(),GWL_STYLE,GetWindowLongPtrA(GetConsoleWindow(), GWL_STYLE) ~WS_SIZEBOX ~WS_MAXIMIZEBOX ~WS_MINIMIZEBOX);
}
七、运行效果 八、不足之处
本系列博文到此告一段落。本程序对于专业做游戏的高手来说都是雕虫小技本人只是初学c随手做了一个小游戏权当练习了。本游戏中定有好多不足之处欢迎给位大神随时指正。本程序最大的不足之处就是由于屏幕刷新引起的闪烁情况。经查阅资料屏幕刷新引起的闪烁问题可以通过双缓存方式予以解决本人已经测试过这种方法只适用于字符是系统默认的白色如果是彩色字符则无能为力。所以后续还需要继续探索其他方法如有大神知道解决方法也敬请赐教。