飞机大战——有图片,有声音

大家好,我是作者:隐匿269今天我带来的是用链表制作游戏,飞机大战(俗称:打飞机小游戏)。我会运用到图形库,没有图形库的伙伴不用着急,把打印图片的步骤省略,代码也能运行。

一、准备(大纲)

编程时,首先要做的就是整理好思路。我们要思考飞机大战的游戏规则,以及飞机的移动,敌机、子弹的创建和销毁等。总的可以分为一下几个环节。

*    1、初始化地图窗口,加载图片,飞机链表结构体的实现,变量的定义
    *    2、生成我放飞机,并移动
    *    3、发射子弹、移动、销毁
        4、敌方飞机生成、移动、销毁
        5、子弹消灭敌机
        6、敌机和我放飞机碰撞
        7、表示游戏结束
        8、计分
        9、背景音乐

二、代码

​
//头文件名称"Airplane.h"
#pragma once
#include <stdio.h>
#include <stdlib.h>

//头文件重复函数

//链表结构的声明和定义

//链表节点结构体的声明
typedef struct Node
{
	int x;//坐标
	int y;//坐标
	int speed;//移动速度
	struct Node*next;//指针域,用于连接下一个节点  
}Node;

//链表结构体的声明
typedef struct Linklist
{
	Node*head;//头部节点指针
	Node*end;//尾部节点指针
}LL;

//链表节点的创建函数
Node *linklist_init(int x, int y, int speed)
{
	Node*temp = (Node*)malloc(sizeof(Node));
	if (temp == NULL)
	{

		return 0;
	}
	temp->speed = speed;
	temp->x = x;
	temp->y = y;
	temp->next = NULL;
	return temp;
}

//链表节点的插入
void linklist_insert(LL*list, int x, int y, int speed)

{
	if (NULL == list)
	{
		return;
	}
	if (list->head == NULL)
	{
		list->head = list->end = linklist_init(x, y, speed);
	}
	else
	{
		list->end->next = linklist_init(x, y, speed);
		list->end = list->end->next;
	}
}


//链表节点的删除函数
void Node_delete(LL*list, Node*p)

{
	if (list == NULL || list->head == NULL)
	{
		return;

	}
	if (p == list->head)
	{
		list->head = p->next;
		free(p);
		return;
	}
	Node*temp = list->head;
	for (; temp; temp = temp->next)
	{
		if (temp->next = p)
		{
			if (p == list->end)
			{
				list->end = temp;
			}
			temp->next = p->next;
			free(p);
			p = NULL;
			return;
		}
	}
}

//链表的释放,销毁
void linklist_dekete(LL*list)

{
	if (list->head == NULL || list == NULL)
	{
		return;
	}
	for (Node*temp1 = list->head; temp1 != NULL;)
	{
		Node*temp2 = temp1;
		temp1 = temp1->next;
		free(temp2);
	}
	list->head = list->end = NULL;
}

​
​
//头文件名称"AirWar.h"
#pragma once
#include"Airplane.h"
//图形库头文件
#include"graphics.h"
#include "stdlib.h"
#include<stdio.h>
#include<conio.h>//_getch()、getch()、_kbhit()头文件
#include<time.h>//时间函数头文件
#include<math.h>//数学函数头文件
#include<tchar.h>//宽字节字符头文件
#define BGWIDETH				400											//窗口、背景宽度
#define BGHIGHT					600											//窗口、背景的高度
#define myPlaneBGWIDETH			50											//我方飞机宽度
#define myPlaneBGHIGHT			75											//我方飞机高度
#define enemyPlaneBGWIDETH		50											//敌方飞机宽度
#define enemyPlaneBGHIGHT		40											//敌方飞机高度
#define BulletBGWIDETH			10											//子弹宽度
#define BulletBGHIGHT			16											//子弹高度
#pragma comment(lib,"winmm.lib")//包含音乐静态库winmm.lib



IMAGE img[4];																 //图片数组
Node myPlane;																 //我方飞机
LL myBullet;																 //我方子弹链表
LL enemyPlane;																 //敌方飞机链表

int isWin;																	 //游戏开始、结束初始化为0
int score;																	 //游戏开始得分初始化为0
	//加载图片
void init()
{
	//定义随机种子
	srand((unsigned)time(NULL));

	loadimage(&img[0], "res\\背景.jpg", BGWIDETH, BGHIGHT);
	loadimage(&img[1], "res\\敌机.jpg", enemyPlaneBGWIDETH, enemyPlaneBGHIGHT);
	loadimage(&img[2], "res\\飞机.jpg", myPlaneBGWIDETH, myPlaneBGHIGHT);
	loadimage(&img[3], "res\\子弹.jpg", BulletBGWIDETH, BulletBGHIGHT);
}

	//初始化我放飞机的坐标和速度
void myPlane_init()
{
	isWin = 0;
	score = 0;
	mciSendString("open res\\JustBlue.mp3", 0, 0, 0);//mciSendString函数用于设置音乐相关选项
	//open加载音乐(打开音乐)
	//打开音乐时需要注意:音乐文件的名称不能含有空客' ',否则无法识别音乐
	//play播报音乐
	mciSendString("play res\\JustBlue.mp3", 0, 0, 0);
	myPlane.x = BGWIDETH/2- enemyPlaneBGWIDETH/2;
	
	myPlane.y = BGHIGHT- myPlaneBGHIGHT -25;
	myPlane.speed = 5;
	myPlane.next = NULL;

	//初始化子弹的坐标和速度
}

//我方子弹生成函数
void creatmyBullet()
{
	linklist_insert(&myBullet, myPlane.x + (myPlaneBGWIDETH / 2) - (BulletBGWIDETH / 2), myPlane.y + (myPlaneBGHIGHT/2)-BulletBGHIGHT, 10);
}

//敌机的生成函数(随机)
void createEnemyPlane()
{
	if ((rand() % 200) == 199)
	linklist_insert(&enemyPlane, rand() % (BGWIDETH- enemyPlaneBGWIDETH), 0 - enemyPlaneBGHIGHT, (rand() % 2)+1);
}

//子弹和敌机的移动
void move()
{
	//子弹移动
	for (Node*temp = myBullet.head; temp; temp = temp->next)
	{//循环遍历整个子弹链表
		temp->y -= temp->speed;
	

	}
	//敌机移动
	for (Node*temp = enemyPlane.head; temp; temp = temp->next)
	{//循环遍历整个敌机链表
		temp->y += temp->speed;
	}
}

//玩游戏函数,我方飞机的移动
void play()
{
	if (_kbhit())
	{
		switch (getch())
		{
			//向上移动
		case 'w':
		case 'W':
			if(myPlane.y>=0)
			myPlane.y -= myPlane.speed;
			break;
			//向左移动
		case 'a':
		case 'A':
			if (myPlane.x>=0)
			myPlane.x -= myPlane.speed;
			break;
			//向右移动
		case 'd':
		case 'D':
			if (myPlane.x<=BGWIDETH- myPlaneBGWIDETH)
			myPlane.x += myPlane.speed;
			break;
			//向下移动
		case 'x':
		case 'X':
			if (myPlane.y <= BGHIGHT- myPlaneBGHIGHT)
			myPlane.y += myPlane.speed;
			break;
			//手动发射子弹
		case 'b':
		case 'B':
			creatmyBullet();
			break;
		}
	}
	
}

//绘制地图
void DrawMap()
{
	BeginBatchDraw();//开始批量绘图
	putimage(0, 0, &img[0]);//绘制背景
	//绘制敌机
	for (Node*temp = enemyPlane.head; temp; temp = temp->next)
	{//循环遍历整个飞机链表
		putimage(temp->x, temp->y, &img[1]);
	}
	
	//绘制飞机
	putimage(myPlane.x, myPlane.y, &img[2]);

	//绘制子弹
	for (Node*temp = myBullet.head; temp; temp = temp->next)
	{//循环遍历整个子弹链表
		putimage(temp->x,temp->y, &img[3]);

	}
	TCHAR str[50];//需要包含头文件tchar.h,能够很好的保存中文,宽字节字符
	//定义一个宽字节字符TCHAR数组str,用于存储即将显示的分数字符串,

	sprintf(str, "当前的分:%d", score);
	//输入函数,将其中 "当前的分:"这个字符串放到宽字节字符TCHAR数组str中,可以使用
	//格式占位符(如:%d、%c%f等)向字符串中插入变量的值
	setbkmode(TRANSPARENT);
	outtextxy(0, 0, str);
	EndBatchDraw();//开始批量绘图
}

//子弹碰撞检测函数
int Blt_isColllision(Node*p,Node*q)
{
	//用中心点判断
	//求子弹中心点坐标
	int px = p->x + BulletBGWIDETH / 2;//x坐标
	int py = p->y + BulletBGHIGHT / 2;//y坐标
	//求敌机中心点坐标
	int qx = q->x + enemyPlaneBGWIDETH / 2;//x坐标
	int qy = q->y + enemyPlaneBGHIGHT / 2;//y坐标
	if (abs(px - qx) >=( (BulletBGWIDETH + enemyPlaneBGWIDETH) / 2)
		|| abs(py - qy) >= ((BulletBGHIGHT + enemyPlaneBGHIGHT) / 2))
	{
		return 0;
	}
	else
	{
		return 1;
	}
}

//敌机、飞机碰撞检测函数
int Air_isColllision(Node*p, Node*q)

{
	//求飞机中心点坐标
	int px = p->x + myPlaneBGWIDETH / 2;//x坐标
	int py = p->y + myPlaneBGHIGHT / 2;//y坐标
	//求敌机中心点坐标
	int qx = q->x + enemyPlaneBGWIDETH / 2;//x坐标
	int qy = q->y + enemyPlaneBGHIGHT / 2;//y坐标
	if (abs(px - qx) >= ((myPlaneBGWIDETH + enemyPlaneBGWIDETH) / 2)
		|| abs(py - qy) >= ((myPlaneBGHIGHT + enemyPlaneBGHIGHT) / 2))
	{
		return 0;
	}
	else
	{
		return 1;
	}
	
}

//子弹销毁和敌机的销毁
void Delete()
{
	for (Node*temp = myBullet.head; temp; temp = temp->next)
	{
		if (temp->y <0- BulletBGHIGHT)
		{//如果子弹的y坐标小于0,则判断子弹移动到屏幕外面,销毁子弹
			Node_delete(&myBullet, temp);//销毁子弹链表
			return;//一次只释放一个节点
		}
		
	}
	
		for (Node*temp2 = enemyPlane.head; temp2; temp2 = temp2->next)
		{
			if (temp2->y > BGHIGHT)
			{//如果子弹的y坐标大于屏幕高度,则判断子弹移动到屏幕外面,销毁子弹
				Node_delete(&enemyPlane, temp2);//销毁子弹链表
				return;//一次只释放一个节点
			}
			for (Node*temp1 = myBullet.head; temp1; temp1 = temp1->next)
			{
				if (Blt_isColllision(temp1, temp2)/*子弹消灭敌机*/)
				{
					Node_delete(&myBullet, temp1);//销毁子弹
					Node_delete(&enemyPlane, temp2);//销毁敌机
					score++;
					return;
				}
			}
			if (Air_isColllision(&myPlane, temp2))
			{
				//如果我方飞机碰到了敌机
				//游戏失败
				isWin = 1;//游戏失败
				return;
			}
		}
	
}





void start()
{
	//打开图形库窗口
	initgraph(BGWIDETH, BGHIGHT);
	//加载图片
	init();
	//初始化飞机数据
	myPlane_init();
	while (1)
	{
		//绘制地图
		DrawMap();
		//移动
		play();
	
	createEnemyPlane();//随机生成敌机
	//子弹和敌机的移动
	move();
	//子弹和敌机的销毁
	Delete();
	if (isWin)
	{
		linklist_dekete(&enemyPlane);//游戏结束,释放整个敌机列表
		linklist_dekete(&myBullet);//游戏结束,释放整个子弹列表
		TCHAR str[50];//需要包含头文件tchar.h,能够很好的保存中文,宽字节字符
	//定义一个宽字节字符TCHAR数组str,用于存储即将显示的分数字符串,

		sprintf(str, "当前的分:%d\n是否重新开始游戏?", score);
		int temp=MessageBox(GetForegroundWindow(), str, "游戏失败", MB_YESNO);
		
		//临时变量temp接受弹窗按键后的返回值
		if (6 == temp)//'6'表示弹窗里按下“是”这个按钮
		{
			init();//重新初始化游戏
			myPlane_init();
		}
		else if(7 == temp)//'7'表示弹窗里按下“否”这个按钮
		{
			break;
		}

	}
	Sleep(10);//延迟一毫秒
	}
	

	closegraph();
}

​
​

#define _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_DEPRECATE
#define _CRT_NONSTDC_NO_DEPRECATE
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#include"AirWar.h"
/*
飞机(我方,敌方),地图,子弹
	*	1、初始化地图窗口,加载图片,飞机链表结构体的实现,变量的定义
	*	2、生成我放飞机,并移动
	*	3、发射子弹、移动、销毁
		4、敌方飞机生成、移动、销毁
		5、子弹消灭敌机
		6、敌机和我放飞机碰撞
		7、表示游戏结束
		8、计分
		9、背景音乐

*/

int main()
{
	start();//开始函数
	system("pause");
	return 0;
}

​

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值