[C/C++/初学者]飞机大战 原神版

前言:

本人现在是一名软件专业的大一学生,
此程序为本校的校内技能大赛-程序设计大赛-专科组参赛作品。

而设计它的初衷也不是为了拿奖,(小声:毕竟我这种简易版飞机大战几乎没什么深度

而是为了加深自己对C语言和C++的理解,也是为了进一步提高自己的编程技术,因为前段时间也是刚刚才完成学生成绩管理系统。

受到时间与技术的双重限制,故只有实现了基本功能,

以下是程序鉴赏环节。

鉴赏:

一、封面

二、菜单界面

三、游戏规则

四、游戏主体

 

素材:

head.h(头文件):

#include<stdio.h>
#include<time.h>
#include<stdlib.h>//包含清屏指令
#include<graphics.h>//图形库头文件
#include<conio.h>   //使用getch(),以获取键盘消息
#include<mmsystem.h>//包含多媒体设备接口的头文件
#pragma comment(lib,"winmm.lib")
#pragma warning (disable :4996)

#define  SIZE 650 //背景大小
#define  PSIZE 80 //飞机大小
#define  MAX 100//子弹数目
#define  FMAX 10//敌机数目

/*

使用布尔类型中的true和false来代表阿影和史莱姆的存活

*/
typedef struct Member
{
	double x;
	double y;
	bool life;  
}mem;

void welcome1();
void gamemenu();
void welcome();
void explation();//游戏规则

void Game();  //游戏进程
void Load();//图片加载
void DataInit();//数据初始化
void PlaneCtr();//通过输入上下左右来改变飞机的坐标
void Show();//画面呈现
void BullterCre();//按了空格,调用函数,创建子弹
void BullterMove();//子弹移动
void FplaneCre();//敌机创建
void FplaneMove();//敌机移动
void Hit();//消灭敌机

void FdieRetain();//击中后效果保留一段时间
void PDie();//被敌机击中
void Score();//分数显示
void BGM();//背景音乐

BGM.cpp(音频函数):

#include<stdio.h>
#include"head.h"

//播放舰桥音乐
void BGM()
{
	//打开音乐
	mciSendString(TEXT("open denglu.mp3"),0,0,0);
	//播放音乐
	mciSendString(TEXT("play denglu.mp3 repeat"),0,0,0);   //repeat控制音频的循环播放
}
#include<stdio.h>
#include"head.h"

 int color(int c)
{
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), c);        //更改文字颜色
	return 0;
}

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

void welcome1()
{
	printf("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■\n");
	printf("■                                                            ■\n");
	printf("■                   ■                  ■      ■           ■\n");
	printf("■        ■  ■          ■  ■           ■  ■             ■\n");
	printf("■      ■■■■■   ■   ■  ■             ■               ■\n");
	printf("■      ■  ■  ■   ■   ■■■   ■■■    ■   ■■■      ■\n");
	printf("■      ■  ■  ■   ■   ■  ■   ■  ■    ■   ■  ■      ■\n");
	printf("■      ■  ■  ■   ■   ■  ■   ■■■    ■   ■■■      ■\n");
	printf("■                                                            ■\n");
	printf("■                TECH OTAKUS SAVE THE WORLD                  ■\n");
	printf("■                                                            ■\n");
	printf("■                       技术宅拯救世界                       ■\n");
	printf("■                                        注:请按下任意键进入■\n");
	printf("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■\n");

	system("pause");
	system("cls");
}

void gamemenu()
{
	time_t TIME;
	struct tm *t;
	TIME=time(0);
	t=localtime(&TIME);

	//SND_FILENAME表示pszSound参数指定的是文件名(pszSound还可以指定资源、内存音乐、系统音乐等等);
	//SND_ASYNC:用异步方式播放声音,PlaySound函数在开始播放后立即返回;
	//SND_SYNC:同步播放声音,在播放完后PlaySound函数才返回;
	//SND_LOOP一遍遍的重复播放声音,必须与SND_ASYNC标志一块使用。

			printf("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■\n");
			printf("■                                                            ■\n");
			printf("■                                                            ■\n");
			printf("■                                                            ■\n");
			printf("■                【欢迎回到提瓦特,旅行者】                  ■\n");
			printf("■                                                            ■\n");
			printf("■                                                            ■\n");
			printf("■                                                            ■\n");
			printf("■              当前时间为:%s\n",asctime(t));
			printf("■                                                            ■\n");
			printf("■                                                            ■\n");
			printf("■                                                            ■\n");
			printf("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■\n");

			system("pause");
			system("cls");
}

//主界面
void welcome()
{
	int n;

	printf("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■\n");
	printf("■             原神战机 Genshin War-Plane  V5.9               ■\n");
	printf("■                                                            ■\n");
	printf("■                                                            ■\n");
	printf("■                      操作选择(Change)                      ■\n");
	printf("■                                                            ■\n");
	printf("■                   1.开始游戏(Play Game)                    ■\n");
	printf("■                   2.游戏规则(Game Rule)                    ■\n");
	printf("■                   3.退出游戏(Exit Game)                    ■\n");
	printf("■                                                            ■\n");
	printf("■                                                            ■\n");
	printf("■                                                            ■\n");
	printf("■制作人: 学号:  联系方式:■\n");
	printf("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■\n");

	color(15);
	gotoxy(20, 15);
	printf("请选择您的操作 1 2 3 4: ");
	scanf("%d", &n);   // 输入选项
	switch (n)
	{
	case 1:
		break;
	case 2:
		explation();   // 游戏规则
		break;
	case 3:
		exit(0);       // 退出游戏
		break;
	default:
		color(8);
		gotoxy(33, 22);
		printf("请输入1-3之间的数");
		_getch();       // 输入任意键
		system("cls");  // 清屏
		welcome();
	}
}

//游戏规则及相关信息
void explation()
{
	system("cls");

	printf("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■\n");
	printf("■                 游戏规则 Rules of game                     ■\n");
	printf("■                                                            ■\n");
	printf("■                                                            ■\n");
	printf("■ ①击败史莱姆可获得1分                                      ■\n");
	printf("■ ②原作:原神——米哈游                                     ■\n");
	printf("■ ③游戏途中可按下Backspace键退出游戏                        ■\n");
	printf("■ ④使用↑↓← → 键分别控制阿影的移动                       ■\n");
	printf("■ ⑤按下空格键即为发射渔获,一发子弹即可消灭史莱姆           ■\n");
	printf("■ ⑥音乐:Genshin Impact Main Theme 原神——陈致逸/HOYO-MiX  ■\n");
	printf("■                                                            ■\n");
	printf("■                   按回车键返回主页面                       ■\n");
	printf("■                                                            ■\n");
	printf("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■\n");

	_getch();  
	system("cls");
	welcome();
}

body.cpp(主体函数):

/*

若解压后发现IMAGE处出现错误,请前往https://easyx.cn/网址,下载easyx图形库
因无法直接使用透明背景图,故此处使用掩码操作实现了类似效果


*/


#include<stdio.h>
#include"head.h"

//定义图片变量
IMAGE bk;//背景图
IMAGE plane_back;//阿影背景图
IMAGE plane_mask;//阿影掩码图
IMAGE fplane_back;//史莱姆背景图
IMAGE fplane_mask;//史莱姆掩码图
IMAGE bullte_back;//子弹背景图
IMAGE bullte_mask;//子弹掩码图
IMAGE fdie_back;//击中史莱姆效果背景图
IMAGE fdie_mask;//击中史莱姆效果掩码图
IMAGE pdie_back;//被击中背景图
IMAGE pdie_mask;//被击中掩码图

//定义全局变量
mem plane;//阿影结构体
mem bullte[MAX];//子弹结构体数组
mem fplane[FMAX];//史莱姆结构体
mem fdie[FMAX];//击中敌机

/*

GetTickCount是返回(retrieve)从操作系统启动所经过(elapsed)毫秒数的函数,
而DWORD则是这个函数的返回值。
此处因为考虑到游戏中常有的无敌时间机制,故查询并考虑了该函数

*/

DWORD b_time_start, b_time_last; //每次发射子弹时的时间间隔

DWORD pf_time_start, pf_time_last; //每次产生史莱姆时的间隔

DWORD p_time_start, p_time_last; //无敌时间

int flag;//本机生命值
int count;//得分计数器
int boom;//爆炸标志


/*
SIZE:
背景图:500*1000

PSIZE:
阿影:100*152
阿影2:100*100
史莱姆:100*65
史莱姆原浆:100*65
渔获:50*200
*/


//图片加载
void Load()
{
	loadimage(&bk, "beijing.jpg");
	
	//加载阿影图片
	loadimage(&plane_back, "plane3.jpg");  //背景
	loadimage(&plane_mask, "plane4.jpg");  //掩码
	
	//加载史莱姆图片	
	loadimage(&fplane_back, "diren1.jpg");
	loadimage(&fplane_mask, "diren2.jpg");

	//记载渔获图片
	loadimage(&bullte_back, "zidan1.jpg");
	loadimage(&bullte_mask, "zidan2.jpg");

	//史莱姆凋落物
	loadimage(&fdie_back, "boom1.jpg");
	loadimage(&fdie_mask, "boom2.jpg");

	//记载阿影相撞
	loadimage(&pdie_back, "plane1.jpg");
	loadimage(&pdie_mask, "plane2.jpg");
}

//数据初始化
void DataInit()
{
	//阿影的数据初始化
	plane.x=200; //阿影起始X位置在背景图的中心,背景的二分之一减去自身的一半
	plane.y=500; //阿影起始Y位置在背景图的中心偏上
	plane.life=true; //阿影出生是存活的

	//渔获初始化
	for (int i=0;i<MAX;i++)
	{
		bullte[i].life = false;//渔获没按空格键前是不存在的
	}

	//时间变化初始化
	b_time_start = b_time_last = GetTickCount();//开机到现在的毫秒数
	pf_time_start = pf_time_last = GetTickCount();
	p_time_start = p_time_last = GetTickCount();//被击中无敌时间变化量

	//史莱姆初始化
	for (int i = 0; i<FMAX; i++)
	{
		fplane[i].life = false;
	}
	//击中史莱姆效果初始化
	for (int i = 0; i < FMAX; i++)
	{
		fdie[i].life = false;
	}

	//生命值初始化
	flag=3;

	//死亡爆炸效果控制
	boom=0;

	//得分计数器
	count=0;

}

//通过键盘改变阿影的坐标
void PlaneCtr()
{
	if (GetAsyncKeyState(VK_UP))//向上移动
	{
		if (plane.y>0)//不能越界
		plane.y-=1;
	}
	if (GetAsyncKeyState(VK_DOWN))//向下移动
	{
		if (plane.y<700)//y最大值600,飞机图片大小为80
		plane.y+=1;
	}
	if (GetAsyncKeyState(VK_LEFT))//向左移动
	{
		if (plane.x>0)//可以缩入墙壁一半机体
		plane.x-=1;
	}
	if (GetAsyncKeyState(VK_RIGHT))//向右移动
	{
		if (plane.x<450)
		plane.x+=1;
	}
	if (GetAsyncKeyState(VK_SPACE) && b_time_last - b_time_start>80)//发射子弹,每颗子弹间接为80毫秒
	{
		BullterCre();//空格发射子弹
		b_time_start = b_time_last;
	}
	b_time_last = GetTickCount();
}

//画面呈现
void Show()
{	
	BeginBatchDraw();//双缓冲绘图,防闪烁

	putimage(0, 0, &bk);
	Score();//分数和生命值显示

	if (plane.life)//飞机存活就打印飞机
	{
		putimage((int)plane.x, (int)plane.y, &plane_mask,NOTSRCERASE);
		putimage((int)plane.x, (int)plane.y, &plane_back,SRCINVERT);
	}
	if (boom)
	{
		putimage((int)plane.x,(int)plane.y, &pdie_mask,NOTSRCERASE);
		putimage((int)plane.x,(int)plane.y, &pdie_back,SRCINVERT);
		if (rand()%80 ==2)
		{
			boom=0;
			//飞机复活
			plane.x=200; //飞机起始位置在背景图的中央
			plane.y=500;
		}
	}
	if (plane.life==false&&boom==0&&flag!=0)
	{
		if (p_time_last-p_time_start>=4000)//无敌时间3秒
		{
			plane.life=true;
			p_time_start=p_time_last;
		}

		p_time_last=GetTickCount();

		putimage((int)plane.x,(int)plane.y, &plane_mask,NOTSRCERASE);
	}
	for (int i=0;i<MAX;i++)//循环判断子弹
	{
		if (bullte[i].life)//子弹存在就打印子弹
		{
			putimage((int)bullte[i].x,(int)bullte[i].y, &bullte_mask,NOTSRCERASE);
			putimage((int)bullte[i].x,(int)bullte[i].y, &bullte_back,SRCINVERT);
		}
	}

	for (int i=0;i<FMAX; i++)
	{
		if (fdie[i].life)//打印击中效果
		{
			putimage((int)fdie[i].x,(int)fdie[i].y, &fdie_mask,NOTSRCERASE);
			putimage((int)fdie[i].x,(int)fdie[i].y, &fdie_back,SRCINVERT);
		}

		if (fplane[i].life)//打印敌机
		{
			putimage((int)fplane[i].x,(int)fplane[i].y, &fplane_mask,NOTSRCERASE);
			putimage((int)fplane[i].x,(int)fplane[i].y, &fplane_back,SRCINVERT);
		}
	}
	EndBatchDraw();
}

//创建渔获
void BullterCre()
{
	for (int i=0;i<MAX;i++)
	{
		if (!bullte[i].life)//子弹不存在就创建子弹
		{
			//从飞机的正前方发出去
			bullte[i].x = plane.x+50;  //宽度:50
			bullte[i].y = plane.y-200;  //长度:200
			bullte[i].life = true;
			break;//一次空格产生一颗子弹
		}
	}
}

//渔获移动
void BullterMove()
{
	for (int i=0;i<MAX;i++)
	{
		if (bullte[i].life)//子弹存在,它的y坐标就减少
		{
			bullte[i].y--;//坐标减,产生移动

			if (bullte[i].y<0)//子弹回收,否则下次全是发射出去的子弹
			{
				bullte[i].life=false;
			}
		}
	}
}

//史莱姆创建
void FplaneCre()
{
	for (int i=0;i<FMAX;i++)
	{
		if (!fplane[i].life&&pf_time_last-pf_time_start>100)//没有敌机就进行构建,用时间函数控制产生速度
		{
			fplane[i].life=true;
			fplane[i].x=rand()%400;//不让敌出现在窗口外,背景的宽度减去飞机的宽度
			fplane[i].y=0;

			pf_time_start=pf_time_last;
			break;//每次一个
		}
		pf_time_last=GetTickCount();//获取新的时间
	}
}

//史莱姆移动
void FplaneMove()
{
	for (int i=0; i<FMAX;i++)
	{
		if (fplane[i].life)
		{
			fplane[i].y+=0.3;//敌机往下走

			if (fplane[i].y>1000)//敌机回收
				fplane[i].life = false;
		}
	}
}

//消灭史莱姆
void Hit()
{
	for (int i=0;i<FMAX;i++)
	{
		if (!fplane[i].life)//不存在则换下一个判断
			continue;

		for (int j=0;j<MAX;j++)
		{
			if (!bullte[j].life)
				continue;//子弹不存在也换下一个判断

			if (bullte[j].x>fplane[i].x//子弹和敌机有交集则都消失
				&&  bullte[j].x<fplane[i].x + PSIZE
				&&bullte[j].y>fplane[i].y
				&&bullte[j].y<fplane[i].y + PSIZE) 
			{
				fdie[i].life=true;//击中效果
				fdie[i].x=fplane[i].x;
				fdie[i].y=fplane[i].y;
				bullte[j].life=false;
				fplane[i].life=false;
				count++;
			}
		}
	}
}

//史莱姆原浆效果 保留一段时间
void FdieRetain()
{
	for (int i=0;i<FMAX;i++)
	{
		if (rand()%40==2)
		{
			fdie[i].life=false;
		}
	}

}

//与史莱姆相撞
void PDie()
{
	for (int i = 0; i < FMAX; i++)
	{
		if (!fplane[i].life)
			continue;

		if (plane.x>fplane[i].x&&plane.x<fplane[i].x + PSIZE&&plane.y>fplane[i].y&&plane.y < fplane[i].y + PSIZE&&plane.life)
		{
			plane.life=false;
			flag-=1;//生命值-1
			boom=1;//输出爆炸图片
			break;
		}
	}
}

//分数显示
void Score()
{
	char myscore[MAX] = "当前得分为:";
	char num[20];
	sprintf(num, "%d", count);
	settextcolor(WHITE);
	outtextxy(0, 0, myscore);//输出分数
	outtextxy(80, 0, num);

	char _myscore[MAX] = "当前生命值:";
	char _num[20];
	sprintf(_num, "%d", flag);
	settextcolor(WHITE);
	outtextxy(0, 50, _myscore);
	outtextxy(90, 50, _num);//输出剩余生命值

}

//游戏进程
void Game()
{
	//加载图片数和初始化数据
	Load();
	DataInit();

	while (1)
	{
		Show();//图像显示
		if(flag==0)break;
		if(GetAsyncKeyState(VK_BACK))
		{
			exit(0);
		}

		PlaneCtr();//操控
		BullterMove();//子弹移动
		FplaneCre();//敌机创建		
		Hit();//判断是否打中敌机
		FplaneMove();//敌机往下走
		FdieRetain();//击中敌机后效果保留一段时间
		PDie();//被敌机击中
	}
}

int main()
{
	BGM();
	welcome1();
	gamemenu();
	welcome();

	initgraph(500, 1000);
	Game();
	getchar();
	return 0;
}

  • 5
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

渡过晚枫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值