easyx图形库6:实现飞机大战:

news2024/11/26 10:33:38

飞机大战

  • 一.飞机大战的基本窗体:
  • 二.飞机大战的主要战斗场景元素:
    • 一.透明图片:
    • 二.精灵对象:
  • 三.主游戏场景的元素:
    • 1.英雄飞机的结构体定义:
    • 2.英雄飞机的代码实现:
    • 3.游戏背景的结构体定义:
    • 4.游戏背景的代码实现:
    • 5.子弹结构体的定义:
    • 6.子弹的代码实现:
    • 7.敌人飞机的共同属性定义:
    • 8.敌人飞机的函数定义:
    • 9.小敌机的属性定义:
    • 10.小敌机的函数定义:
    • 11.中敌机的属性定义:
    • 12.中敌机的函数实现:
    • 13.大敌机的的属性定义:
    • 14.大敌机的函数定义:
    • 15.音乐的属性定义:
    • 16.音乐播放的相关函数:
  • 四.主要游戏场景的绘制:
    • 1.加入英雄飞机和背景到主要场景中:
    • 2.使用场景(飞机+背景)的对象:
    • 3.加入子弹到我们的主要场景中:
    • 4.使用场景(飞机+背景+子弹)的对象:
    • 5.加入大中小敌人飞机到场景中:
    • 6.子弹射击到敌人飞机检查![请添加图片描述](https://img-blog.csdnimg.cn/9fbb9b8fe24047689d58dab0ad25ea81.png)
    • 7.子弹碰撞到敌人飞机的爆炸检查:
    • 8.在游戏场景中加入音乐:
    • 9.在对应位置播放关闭音乐和添加成绩:
    • 10.一次游戏结束打印总成绩(并且等待一定的时间回到菜单:)
  • 五.菜单场景:

一.飞机大战的基本窗体:

在这里插入图片描述

二.飞机大战的主要战斗场景元素:

请添加图片描述

一.透明图片:

请添加图片描述
请添加图片描述
image.h和image.cpp

#pragma once
#include<easyx.h>
void PutTransParentTmage(int x, int y, const IMAGE* mask, const IMAGE* img);

///

#include"image.h"
void PutTransParentTmage(int x, int y, const IMAGE* mask, const IMAGE* img)
{
	//按位与
	putimage(x, y, mask, SRCAND);
	//按位或
	putimage(x, y, img, SRCPAINT);
}

二.精灵对象:

图片相关的准备工作完成后,我们开始想想如何用代码实现这个游戏。回忆一下之前讲过的关于面向对象风格编程的理论。我们把上述的图形元素的共性提取出来,成为一个基础对象,其他对象均继承于这个基础对象。游戏编程中,我们常常把游戏中出现的各种图形元素称作“精灵”。因此,我们把这个基础对象命名为 sprite 。
精灵它们都会在屏幕中移动,肯定需要记录当前的坐标。另外,它们所占有的大小各不相同,也就是拥有自己的宽度和高度。
除此之外,精灵都是需要被绘制到画面上的,所以精灵拥有一个名为 draw 的方法。精灵不能总是待在一个地方不动。所以,精灵还需要一个 update 方法,用于更新精灵内部的数据。后续的代码中,我们会保证每一帧都执行一次每一个精灵的 draw 方法和 update 方法。这样,我们就能保证所有精灵都被正常绘制,并且数据被及时的更新

sprite.h

struct sprite {
	//函数指针保存方法:
	void(*draw)(struct sprite*);
	void(*updata)(struct sprite*);
	//基本数据:
	int x;
	int y;

	int width;
	int hight;
};

三.主游戏场景的元素:

1.英雄飞机的结构体定义:

1.我们的父目录:
两个方法,x,y,宽和高;
2.两个图像(mask+img)的指针数组:
3.飞机的状态:
4.飞机的生命数值值:
5.飞机或者的计数器(作用:不要让飞机生成的太快:)

#pragma once

#include<easyx.h>
#include"sprite.h"

//枚举类型可以和图片的状态非常好的联系起来:

enum herostate {
	//普通状态
	hero_normal0,
	hero_normal1,
	//毁坏过程
	hero_down0,
	hero_down1,
	hero_down2,
	hero_down3,
	//销毁状态:
	hero_destory
};


struct hero {
	//作为基本的成员变量:
	struct sprite super;
	//两个图片
	IMAGE* heromask[6];
	IMAGE* heroimg[6];
	//状态:
	enum herostate state;
	//生命数值:
	int lift;
	//记数器
	int heroUpdataCnt;
};

//初始化英雄飞机:
void heroInit(struct hero* h);

//销毁英雄飞机:
void heroDestory(struct hero* h);

2.英雄飞机的代码实现:

1.写draw和updata方法:
2.对英雄飞机对象的初始化和方法:
3.英雄飞机中的图片数组初始化需要注意:

#include"image.h"
#include"hero.h"
#include<stdio.h>

//给一个数组去控制我们英雄飞机的状态变化:
enum herostate Airdesstchan[7] = {
	//普通状态
	hero_normal0,
	hero_normal1,
	//毁坏过程
	hero_down0,
	hero_down1,
	hero_down2,
	hero_down3,
	//销毁状态:
	hero_destory
};



void heroraw(struct hero* s)
{
	//绘制透明图片的函数:
	//状态使用枚举类型可以通过下标找到对应绘制的图片:
	PutTransParentTmage(s->super.x, s->super.y,
		s->heromask[s->state], s->heroimg[s->state]);
}

void heroupdata(struct hero* s)
{
	//状态的变化:
	//使用计数器

	s->heroUpdataCnt++;
	if (s->heroUpdataCnt >= 15)
	{
		s->heroUpdataCnt=0;

		//1.普通状态:
		if (s->lift != 0)
		{
			//状态变化的尾火焰喷射效果
			if (s->state == hero_normal0)
				s->state = hero_normal1;
			else if (s->state == hero_normal1)
				s->state == hero_normal0;
		}
		//2.销毁状态:
		else
		{
			//进行状态变化(到destory之前都可以变化):
			if (s->state < hero_destory)
			{
				s->state = Airdesstchan[s->state + 1];
			}
		}

	}
}

//初始化英雄飞机:
void heroInit(struct hero* h)
{
	//两个方法初始化好了
	h->super.draw = (void(*)(struct sprite*))heroraw;
	h->super.updata = (void(*)(struct sprite*))heroupdata;
	
	//坐标
	h->super.x = 178;
	h->super.y = 600;

	//常量:
	//状态:
	h->state=hero_normal0;
	//生命数值:
	h->lift=1;
	//记数器
	h->heroUpdataCnt=0;

	//image是c++声明的结构体类型,创建指针是要使用new
	for (int i = 0; i < 6; i++)
	{
		h->heroimg[i] = new IMAGE;
		h->heromask[i] = new IMAGE;
	}

	//存放路径:
	char img[100];
	char imgMask[100];
	//普通状态
	for (int i=0 ; i < 2 ; i++)
	{
		//1.创建:
		sprintf(img, "img/hero/hero%d.png", i);
		sprintf(imgMask, "img/hero/hero%d_mask.png", i);
		//2.加载
		loadimage(h->heroimg[i], img);
		loadimage(h->heromask[i], imgMask);
	}
	//销毁状态
	for (int i = 0; i < 4; i++)
	{
		//1.创建:
		sprintf(img, "img/hero/hero_down%d.png", i);
		sprintf(imgMask, "img/hero/hero_down%d_mask.png", i);
		//2.加载
		loadimage(h->heroimg[i+2], img);
		loadimage(h->heromask[i+2], imgMask);
	}
}

//销毁英雄飞机:
void heroDestory(struct hero* h)
{
	//new创建delete销毁
	for (int i = 0; i < 6; i++)
	{
		delete h->heroimg[i];
		delete h->heromask[i];
	}
}

3.游戏背景的结构体定义:

1.精灵的父对象:
2.图片指针:
请添加图片描述

background.h

#include<easyx.h>
#include"sprite.h"

struct background {
	//父对象
	struct sprite super;

	int yA;
	int yB;

	//背景图像的指针:
	IMAGE* bk;
};

void backgroundInit(struct background* b);

void backgroundDestory(struct background* b);

4.游戏背景的代码实现:

background.cpp

#include"background.h"

void Drawbackground(struct background* b)
{
	//两个背景图片的绘制:
	putimage(0, b->yA, b->bk);
	putimage(0, b->yB, b->bk);
}

void Updatabackground(struct background* b)
{
	//1.移动图片:
	b->yA = b->yA + 1;
	b->yB = b->yB + 1;
	//2.判断第一张图片的位置进行重置:
	if (b->yB >= 0)
	{
		b->yA = 0;
		b->yB = -750;
	}
}

void backgroundInit(struct background* b)
{
	b->super.draw = (void(*)(struct sprite*))Drawbackground;
	b->super.updata = (void(*)(struct sprite*))Updatabackground;

	b->yB = -750;
	b->yA = 0;

	b->bk=new IMAGE;
	loadimage(b->bk, "img/bg.png");
}

void backgroundDestory(struct background* b)
{
	delete b->bk;
}

5.子弹结构体的定义:


#include"image.h"
#include"sprite.h"


struct bullet {
	struct sprite supper;
	//子弹的图片:
	IMAGE* bulletimg;
	IMAGE* bulletimgmask;
};

void bulletInit(struct bullet* b);
void bulletDestory(struct bullet* b);

6.子弹的代码实现:

#include"bullet.h"
#include"image.h"

void bulletDraw(struct bullet* b)
{
	//绘制子弹
	PutTransParentTmage(b->supper.x, b->supper.y,
		b->bulletimgmask, b->bulletimg);
}

void bulletUpdata(struct bullet* b)
{
	b->supper.y = b->supper.y - 8;
}

void bulletInit(struct bullet* b)
{
	b->supper.draw=(void(*)(sprite*))bulletDraw;
	b->supper.updata = (void (*)(sprite*))bulletUpdata;

	//new两个图片指针:
	b->bulletimg=new IMAGE;
	b->bulletimgmask = new IMAGE;

	//加载图片:
	loadimage(b->bulletimg, "img/bullet/bullet.png");
	loadimage(b->bulletimgmask, "img/bullet/bullet_mask.png");
}
void bulletDestory(struct bullet* b)
{
	delete b->bulletimg;
	delete b->bulletimgmask;
}

7.敌人飞机的共同属性定义:

#include"sprite.h"
#include<easyx.h>

//枚举大中小敌人飞机:
enum enemyType {
	enemType0,
	enemType1,
	enemType2
};

//枚举大中小敌人飞机的各种状态:
enum ememyStatus {
	//正常状态
	enemy_normal,
	//爆炸状态
	enemy_down0,
	enemy_down1,
	enemy_down2,
	enemy_down3,
	enemy_down4,
	enemy_down5,
	//销毁状态
	enemy_destory
};

//敌人飞机的共性:

struct enemy {
	struct sprite super;
	//敌人飞机击中之后的处理:
	void(*hited)(struct enemy*);
	
	//销毁敌人飞机
	void(*destory)(struct enemy*);

	//图像指针数组,动态开辟:
	IMAGE** imgArrEnemy;
	IMAGE** imgArrEnemyMask;

	//敌人飞机的种类
	enum enemyType enemType;
	//速度
	int v;
	//生命值
	int lift;
	//计数器
	int enemyDownCnt;
	//状态
	int status;

	//销毁之前最后一个状态;
	int lastStatusBeforeDestory;
};

8.敌人飞机的函数定义:

#define _CRT_SECURE_NO_WARNINGS 1

#include"image.h"
#include"enemy.h"
#include<time.h>

//状态变化
static enum enemyStatus enemyStatusSequence[8] = {
	//正常状态
	enemy_normal,
	//爆炸状态
	enemy_down0,
	enemy_down1,
	enemy_down2,
	enemy_down3,
	enemy_down4,
	enemy_down5,
	//销毁状态
	enemy_destory
};

//1.super中的绘制
void enemyDraw(struct enemy* e)
{
	//拿到对应图片的指针绘制出来就可以了:
	IMAGE* imgEnemy = e->imgArrEnemy[e->status];
	IMAGE* imgEnemyMask = e->imgArrEnemyMask[e->status];

	PutTransParentTmage(e->super.x, e->super.y, imgEnemyMask, imgEnemy);
}

//2.super中的更新数据:
void enemyUpdata(struct enemy* e)
{
	//位置的改变
	e->super.y += e->v;

	if (e->lift == 0)
	{
		//飞机的连续炸裂不要一瞬间完成:
		//减缓飞机状态的切换;
		e->enemyDownCnt++;
		if (e->enemyDownCnt >= 15)
		{
			e->enemyDownCnt = 0;
			if (e->status < e->lastStatusBeforeDestory)
			{
				//飞机爆炸状态的变化:
				e->status = enemyStatusSequence[e->status + 1];
			}
			else
			{
				//需要变化所以直接变化:
				e->status = enemy_destory;
			}
		}
	}
}

//3.敌人飞机被击中后的变化
void enemyHited(struct enemy* e)
{
	e->lift--;
	if (e->lift == 0)
		e->status = enemy_down0;
}

//初始化敌人飞机:

void enemyInit(struct enemy* e)
{
	//初始对象方法:
	e->super.draw = (void(*)(sprite*))enemyDraw;
	e->super.update = (void(*)(sprite*))enemyUpdata;
	e->hited = (void(*)(struct enemy*))enemyHited;

	//获取当前时间作为随机数种子的:
	srand((unsigned int)time(NULL));

	//初始化一些数值:
	e->enemyDownCnt = 0;
	e->status = enemy_normal;

	int m = 1;
	int n = 3;
	e->v = rand() % (n - m + 1) + m;

}

9.小敌机的属性定义:

enemy0.h

#include"enemy.h"



struct enemy0 {
	//父目录所有的共性:
	struct enemy super;
};

void enemy0Init(struct enemy0*);

10.小敌机的函数定义:

enemy0.cpp

#include"enemy0.h"
#include"image.h"
#include<stdio.h>

void enemy0destory(struct enemy0* e)
{
	//图片指针的销毁:
	for (int i = 0; i < 5; i++)
	{
		delete e->super.imgArrEnemy[i];
		delete e->super.imgArrEnemyMask[i];
	}

	//销毁图片数组:
	free(e->super.imgArrEnemy);
	free(e->super.imgArrEnemyMask);
	e->super.imgArrEnemy;
	e->super.imgArrEnemyMask;
}

void enemy0Init(struct enemy0* e)
{
	//初始化共性方法:
	enemyInit((struct enemy*)e);
	//销毁函数:
	e->super.destory = (void(*)(struct enemy*))enemy0destory;


	//初始化一些共性数据:
	e->super.super.width = 34;
	e->super.super.hight = 26;
	//敌人飞机类型:
	e->super.enemType = enemType0;
	//敌人飞机的血量:
	e->super.lift = 1;
	//销毁之前的最后一个状态:
	e->super.lastStatusBeforeDestory = enemy_down3;


	//初始化图片数组:
	e->super.imgArrEnemy = (IMAGE**)malloc(sizeof(IMAGE*)*5);
	e->super.imgArrEnemyMask = (IMAGE**)malloc(sizeof(IMAGE*)*5);

	//图片指针的初始化:
	for (int i = 0; i < 5; i++)
	{
		e->super.imgArrEnemy[i] = new IMAGE;
		e->super.imgArrEnemyMask[i] = new IMAGE;
	}

	char enemy0img[100];
	char enemy0imgmask[100];
	//敌人飞机的图片:
	loadimage(e->super.imgArrEnemy[0], "img/enemy0/enemy0.png");
	loadimage(e->super.imgArrEnemyMask[0], "img/enemy0/enemy0_mask.png");
	for (int i = 0; i < 4; i++)
	{
		//格式化输入位置到字符串中:
		sprintf(enemy0img, "img/enemy0/enemy_down%d.png", i);
		sprintf(enemy0imgmask, "img/enemy0/enemy_down%d_mask.png", i);

		loadimage(e->super.imgArrEnemy[i + 1], enemy0img);
		loadimage(e->super.imgArrEnemyMask[i + 1], enemy0imgmask);

	}

}

11.中敌机的属性定义:

enemy1.h


#include"enemy.h"

struct enemy1 {
	//父目录所有的共性:
	struct enemy super;
};

void enemy1Init(struct enemy1*);

12.中敌机的函数实现:

enemy1.cpp

#include"enemy0.h"
#include"image.h"
#include<stdio.h>

void enemy1destory(struct enemy0* e)
{
	//图片指针的销毁:
	for (int i = 0; i < 5; i++)
	{
		delete e->super.imgArrEnemy[i];
		delete e->super.imgArrEnemyMask[i];
	}

	//销毁图片数组:
	free(e->super.imgArrEnemy);
	free(e->super.imgArrEnemyMask);
	e->super.imgArrEnemy;
	e->super.imgArrEnemyMask;
}

void enemy1Init(struct enemy0* e)
{
	//初始化共性方法:
	enemyInit((struct enemy*)e);
	//销毁函数:
	e->super.destory = (void(*)(struct enemy*))enemy1destory;


	//初始化一些共性数据:
	e->super.super.width = 46;
	e->super.super.hight = 59;
	//敌人飞机类型:
	e->super.enemType = enemType1;
	//敌人飞机的血量:
	e->super.lift = 3;
	//销毁之前的最后一个状态:
	e->super.lastStatusBeforeDestory = enemy_down3;


	//初始化图片数组:
	e->super.imgArrEnemy = (IMAGE**)malloc(sizeof(IMAGE*)*5);
	e->super.imgArrEnemyMask = (IMAGE**)malloc(sizeof(IMAGE*)*5);

	//图片指针的初始化:
	for (int i = 0; i < 5; i++)
	{
		e->super.imgArrEnemy[i] = new IMAGE;
		e->super.imgArrEnemyMask[i] = new IMAGE;
	}

	char enemy1img[100];
	char enemy1imgmask[100];
	//敌人飞机的图片:
	loadimage(e->super.imgArrEnemy[0], "img/enemy1/enemy1.png");
	loadimage(e->super.imgArrEnemyMask[0], "img/enemy1/enemy1_mask.png");
	for (int i = 0; i < 4; i++)
	{
		//格式化输入位置到字符串中:
		sprintf(enemy1img, "img/enemy1/enemy1_down%d.png", i);
		sprintf(enemy1imgmask, "img/enemy1/enemy1_down%d_mask.png", i);

		loadimage(e->super.imgArrEnemy[i + 1], enemy1img);
		loadimage(e->super.imgArrEnemyMask[i + 1], enemy1imgmask);

	}

}

13.大敌机的的属性定义:

enemy2.h

#include"enemy.h"

struct enemy2 {
	//父目录所有的共性:
	struct enemy super;
};

void enemy0Init(struct enemy2*);

14.大敌机的函数定义:

enemy2.cpp

#include"enemy2.h"
#include"image.h"
#include<stdio.h>

void enemy0destory(struct enemy2* e)
{
	//图片指针的销毁:
	for (int i = 0; i < 7; i++)
	{
		delete e->super.imgArrEnemy[i];
		delete e->super.imgArrEnemyMask[i];
	}

	//销毁图片数组:
	free(e->super.imgArrEnemy);
	free(e->super.imgArrEnemyMask);
	e->super.imgArrEnemy;
	e->super.imgArrEnemyMask;
}

void enemy0Init(struct enemy2* e)
{
	//初始化共性方法:
	enemyInit((struct enemy*)e);
	//销毁函数:
	e->super.destory = (void(*)(struct enemy*))enemy0destory;


	//初始化一些共性数据:
	e->super.super.width = 109;
	e->super.super.hight = 162;
	//敌人飞机类型:
	e->super.enemType = enemType2;
	//敌人飞机的血量:
	e->super.lift = 5;
	//销毁之前的最后一个状态:
	e->super.lastStatusBeforeDestory = enemy_down5;


	//初始化图片数组:
	e->super.imgArrEnemy = (IMAGE**)malloc(sizeof(IMAGE*)*7);
	e->super.imgArrEnemyMask = (IMAGE**)malloc(sizeof(IMAGE*)*7);

	//图片指针的初始化:
	for (int i = 0; i < 7; i++)
	{
		e->super.imgArrEnemy[i] = new IMAGE;
		e->super.imgArrEnemyMask[i] = new IMAGE;
	}

	char enemy2img[100];
	char enemy2imgmask[100];
	//敌人飞机的图片:
	loadimage(e->super.imgArrEnemy[0], "img/enemy2/enemy2.png");
	loadimage(e->super.imgArrEnemyMask[0], "img/enemy2/enemy2_mask.png");
	for (int i = 0; i < 6; i++)
	{
		//格式化输入位置到字符串中:
		sprintf(enemy2img, "img/enemy2/enemy2_down%d.png", i);
		sprintf(enemy2imgmask, "img/enemy2/enemy2_down%d_mask.png", i);

		loadimage(e->super.imgArrEnemy[i + 1], enemy2img);
		loadimage(e->super.imgArrEnemyMask[i + 1], enemy2imgmask);

	}

}

15.音乐的属性定义:

#include"vector.h"


struct music {
	//打开音频文件:
	void (*play)(struct music*);
	//关闭音频文件
	void (*close)(struct music*, int interval);
	//顺序表存放音频文件的别名:
	vector name;
	//记录文件路径
	char halfway[100];
};

void musicInit(struct music* m, const char*);

void musicDestory(struct music* m);

16.音乐播放的相关函数:

#include"music.h"
#include<easyx.h>
#include<stdio.h>


//播放音乐:
void soundPlay(struct music* e)
{
	//GetTickCount()获取当前时间
	int name= GetTickCount();
	int* music_name = (int*)malloc(sizeof(int));

	if (music_name == NULL)
	{
		perror("malloc file");
		exit(-1);
	}

	*music_name = name;
	e->name.append(&e->name, music_name);

	char command[100];

	//给当前打开的音乐创建一个别名(alias)
	sprintf(command, "open %s alias %d", e->halfway, name);
	mciSendString(command, NULL, 0, NULL);

	sprintf(command, "play %d", name);
	mciSendString(command, NULL, 0, NULL);
}

//关闭音乐:
void soundclos(struct music* m, int interval)
{
	int time = GetTickCount();
	char command[100];

	for (int i = 0; i < m->name.size; i++)
	{
		//每一个音乐开始的时间都看一下:
		int* te = (int*)m->name.get(&m->name, i);

		//歌曲时间
		if (time - *te < interval)
			continue;

		sprintf(command, "close %d", *te);
		mciSendString(command, NULL, 0, NULL);
		m->name.remove(&m->name, i);
		free(te);
		i--;
	}

	
}

void musicInit(struct music* m, const char* soundPath)
{
	m->play = (void (*)(music*))soundPlay;
	m->close = (void (*)(music*,int))soundclos;

	vectorInit(&m->name);
	strcpy(m->halfway, soundPath);
}

void musicDestory(struct music* m)
{
	char command[100];
	//free一个音乐之前应该把它停止播放:
	for (int i = 0; i < m->name.size; i++)
	{
	//销毁每一个别名:
		int* PAlias = (int*)m->name.get(&m->name, i);
		sprintf(command, "close %d", *PAlias);
		mciSendString(command, NULL, 0, NULL);
		free(PAlias);
	}
	vectorDestroy(&m->name);
}

四.主要游戏场景的绘制:

1.对于一个代码来说写一部分运行一部分这样如果有错误也可以及时的发现:
2.定义一个场景对象:
3.实现对于一个场景的绘制,数据更新,鼠标消息,判断场景结束:

scene.h

#pragma once

//场景函数的定义

#include<easyx.h>

struct scene {
	//绘制
	void (*draw)(struct scene*);
	//数据更新
	void (*update)(struct scene*);
	//鼠标消息的获取
	void (*control)(struct scene*, ExMessage* msg);
	//判断场景是否结束
	bool (*isQuit)(struct scene*);
};

1.加入英雄飞机和背景到主要场景中:

1.主要场景的对象:
2.成员变量:
1.场景对象必备父成员
2.英雄飞机:……
3.背景图片……

vector.h和vector.cpp

struct vector {
	//方法和内容的结合
	bool (*append)(struct vector* Pvec, void* newstu);//添加数据
	void* (*get)(struct vector* Pvec, int index);//获取数据
	void (*clear)(struct vector* Pvec);//清楚数据
	void (*remove)(struct vector* Pvec, int index);//删除数据

	void** PData;
	int size;
	int capacity;
};

bool append(struct vector* Pvec, void* newstu);
void* get(struct vector* Pvec, int index);
void clear(struct vector* Pvec);
void remove(struct vector* Pvec, int index);
void vectorDestroy(struct vector* Pvec);
void vectorInit(struct vector* Pvec);

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
#include"vector.h"

#define Init 1

bool append(struct vector* Pvec,void* newstu)
{
	assert(Pvec!=NULL);

	//判断空间是否足够(不够需要增容):
	if (Pvec->size >= Pvec->capacity)
	{
		void** tmp = NULL;
		tmp = (void**)realloc(Pvec->PData,sizeof(void*)*((Pvec->capacity) * 2));
		if (tmp == NULL)
		{
			perror("realloc file\n");
			exit(-1);
		}
		//增容成功:
		Pvec->PData = tmp;
		//容量变化:
		Pvec->capacity = Pvec->capacity * 2;
	}

	//尾插数据:
	Pvec->PData[Pvec->size] = newstu;
	Pvec->size++;
	return true;
}

void* get(struct vector* Pvec, int index)
{
	assert(Pvec != NULL);
	//获取数据要有数据:
	if (Pvec->size == 0)
		return NULL;

	//结构体动态开辟在堆区的一个地址:
	//顺序表是一个结构体指针类型的顺序表:
	return (Pvec->PData[index]);
}

void clear(struct vector* Pvec)
{
	//清除原来的数据
	assert(Pvec);
	free(Pvec->PData);
	Pvec->PData = NULL;
	Pvec->size = 0;
	Pvec->capacity = 0;

	//为新的数据加入做准备
	Pvec->PData = (void**)malloc(sizeof(void*) * Init);
	Pvec->size = 0;
	Pvec->capacity = Init;
}


void remove(struct vector* Pvec, int index)
{
	assert(Pvec != NULL);
	//删除是需要移动数组元素内容的:
	//考虑数组越界的问题:

	//1.假设循环一次都进入不了说明是尾删:
	for (int i = index; i <(Pvec->capacity)-1 ; i++)
	{
		Pvec->PData[i] = Pvec->PData[i + 1];
	}
	//2.直接进行数量的--;
	Pvec->size--;
}
//销毁数组
void vectorDestroy(struct vector* Pvec)
{
	assert(Pvec);

	free(Pvec->PData);
	Pvec->PData = NULL;
	Pvec->size = 0;
	Pvec->capacity = 0;
}


//3.初始化顺序表

void vectorInit(struct vector* Pvec)
{
	Pvec->append = append;
	Pvec->get = get;
	Pvec->clear = clear;
	Pvec->remove = remove;


	Pvec->PData = (void**)malloc(sizeof(void*) * Init);
	Pvec->size = 0;
	Pvec->capacity = Init;
}

思路一:
1.引入一个顺序表,去保存我们的英雄对象和背景对象:
2.在主要场景中引入一个顺序表成员变量:
3.通过对一个顺序表的循环遍历去实现绘制飞机和场景:

mainscene.h

#include"hero.h"
#include"scene.h"
#include"vector.h"
#include"background.h"

struct mainscene {
	//场景必备:
	struct scene super;
	//飞机
	struct hero* hero;
	//背景
	struct background* bk;
	//元素:背景+飞机
	struct vector vecElements;
};

//初始化
void mainsceneInit(struct mainscene* m);
//销毁
void mainsceneInit(struct mainscene* m);

mainscene.cpp

#include"mainscene.h"
#include"hero.h"
#include<stdlib.h>

//1.场景元素的绘制:
void mainSceneDraw(struct mainscene* s)
{
	//顺序表中有背景和英雄就可以了:
	s->vecElements.clear(&s->vecElements);

	//1.加入bk和hero到顺序表中:
	s->vecElements.append(&s->vecElements, s->hero);
	s->vecElements.append(&s->vecElements, s->bk);

	for (int i = 0; i < s->vecElements.size; i++)
	{
		//获取数据
		struct sprite* tmp = (struct sprite*)( &s->vecElements.PData[i]);
		//绘制数据
		tmp->draw(tmp);
	}
}

//2.场景数据的更新:
void mainScenceUpdata(struct mainscene* s)
{
	for (int i = 0; i < s->vecElements.size; i++)
	{
		//获取数据
		struct sprite* tmp = (struct sprite*)(&s->vecElements.PData[i]);
		//更新数据
		tmp->updata(tmp);
	}

}
//3.获取鼠标消息
void mainSceneCountrol(struct mainscene* s, ExMessage* msg)
{
	if (msg->message == WM_MOUSEMOVE)
	{
		//把鼠标当前坐标设置为英雄飞机的坐标
		s->hero->super.x = msg->x - 35;
		s->hero->super.y = msg->y - 35;
	}
}

//4.hero飞机的状态判断:
bool mainSceneIsQuit(struct mainscene* s)
{
	if (s->hero->state == hero_destory)
		return true;

	return false;
}


//初始化
void mainsceneInit(struct mainscene* m)
{
	m->super.draw = (void(*)(scene*))mainSceneDraw;
	m->super.update = (void(*)(scene*))mainScenceUpdata;
	m->super.control = (void(*)(scene*,ExMessage*))mainSceneCountrol;
	m->super.isQuit = (bool(*)(scene*))mainSceneIsQuit;

	//初始化背景:
	m->bk = (struct background*)malloc(sizeof(struct background));
	backgroundInit(m->bk);
	//初始化英雄飞机:
	m->hero = (struct hero*)malloc(sizeof(struct hero));
	heroInit(m->hero);

	//初始化场景和飞机的数组:
	vectorInit(&m->vecElements);

}
//销毁
void mainsceneDestory(struct mainscene* m)
{
	free(m->bk);
	free(m->hero);
	m->bk = NULL;
	m->hero = NULL;
}

2.使用场景(飞机+背景)的对象:

1.背景的一个打印和移动:
2.英雄飞机通过鼠标进行移动:

main.cpp

#include<stdio.h>
#include<easyx.h>
#include"mainscene.h"
#include"gloop.h"

int main()
{
	initgraph(422, 750);
	setbkcolor(WHITE);
	cleardevice();

	struct mainscene ma;
	mainsceneInit(&ma);
	gloop((struct scene*)&ma);
	mainsceneDestory(&ma);



	getchar();
	closegraph();
	return 0;
}

spritegloop.cpp


#include"scene.h"
#include<stdio.h>
#include"gloop.h"
#include<easyx.h>

void gloop(struct scene* s)
{
	//开启批量绘制
	timeBeginPeriod(1);
	BeginBatchDraw();
	while (1)
	{
		cleardevice();

		s->draw(s);
		s->update(s);


		if (s->isQuit(s))
		{
			break;
		}

		Sleep(10);

		//获取鼠标消息:
		//鼠标移动的一个坐标消息:
		ExMessage msg;
		bool isok = peekmessage(&msg, EX_MOUSE);

		//没有鼠标移动不需要控制移动:
		if (isok)
		{
			s->control(s, &msg);
		}
		FlushBatchDraw();
	}

	EndBatchDraw();
	timeEndPeriod(1);
}

3.加入子弹到我们的主要场景中:

#include"mainscene.h"
#include"hero.h"
#include<stdlib.h>
#include"bullet.h"

//1.场景元素的绘制:
void mainSceneDraw(struct mainscene* s)
{
	//顺序表中有背景和英雄就可以了:
	s->vecElements.clear(&s->vecElements);

	//1.加入bk和hero到顺序表中:
	s->vecElements.append(&s->vecElements, s->bk);
	s->vecElements.append(&s->vecElements, s->hero);


	//2.加入子弹到我们的顺序表中:
	for (int i = 0; i < s->vecBullets.size; i++)
	{
		struct bullet* tmp = (struct bullet*)s->vecBullets.get(&s->vecBullets, i);
		s->vecElements.append(&s->vecElements, tmp);
	}

	for (int i = 0; i < s->vecElements.size; i++)
	{
		//获取数据
		struct sprite* tmp = (struct sprite*)(s->vecElements.PData[i]);
		//绘制数据
		tmp->draw(tmp);
	}
}

//2-1子弹数据的初始化:
void generaBullet(struct mainscene* b)
{
	//每一颗子弹进行初始化:
	struct bullet* PBullet = (struct bullet*)malloc(sizeof(struct bullet));
	if (PBullet == NULL)
	{
		perror("malloc file");
		exit(-1);
	}

	bulletInit(PBullet);
	//根据英雄飞机去初始化子弹的位置:
	PBullet->super.x = b->hero->super.x + 32;
	PBullet->super.y = b->hero->super.y - 6;

	//添加到顺序表中:
	b->vecBullets.append(&b->vecBullets, PBullet);
}

//2-2:子弹数据的一个删除
void destorygeneraBullet(struct mainscene* b)
{
	//1.要有数据才可以删除数据
	if (b->vecBullets.size <= 0)
	{
		return;
	}

	//获取头子弹:
	struct bullet* tmp = (struct bullet*)b->vecBullets.get(&b->vecBullets, 0);

	if (tmp->super.y < -14)
	{
		//头删
		b->vecBullets.remove(&b->vecBullets, 0);
		bulletDestory(tmp);
		free(tmp);
	}


}
//2.场景数据的更新:
void mainScenceUpdata(struct mainscene* s)
{
	for (int i = 0; i < s->vecElements.size; i++)
	{
		//获取数据
		struct sprite* tmp = (struct sprite*)(s->vecElements.PData[i]);
		//更新数据
		tmp->updata(tmp);
	}

	//添加子弹:
	s->bulletGerncnt++;
	if (s->bulletGerncnt >= 15)
	{
		generaBullet(s);
		s->bulletGerncnt = 0;
	}
	//判断子弹是否可以销毁:
	destorygeneraBullet(s);

}
//3.获取鼠标消息
void mainSceneCountrol(struct mainscene* s, ExMessage* msg)
{
	if (msg->message == WM_MOUSEMOVE)
	{
		//把鼠标当前坐标设置为英雄飞机的坐标
		s->hero->super.x = msg->x - 35;
		s->hero->super.y = msg->y - 35;
	}
}

//4.hero飞机的状态判断:
bool mainSceneIsQuit(struct mainscene* s)
{
	if (s->hero->state == hero_destory)
		return true;

	return false;
}


//初始化
void mainsceneInit(struct mainscene* m)
{
	m->super.draw = (void(*)(scene*))mainSceneDraw;
	m->super.update = (void(*)(scene*))mainScenceUpdata;
	m->super.control = (void(*)(scene*,ExMessage*))mainSceneCountrol;
	m->super.isQuit = (bool(*)(scene*))mainSceneIsQuit;

	//初始化背景:
	m->bk = (struct background*)malloc(sizeof(struct background));
	backgroundInit(m->bk);
	//初始化英雄飞机:
	m->hero = (struct hero*)malloc(sizeof(struct hero));
	heroInit(m->hero);

	//初始化场景和飞机的数组:
	vectorInit(&m->vecElements);
	//初始化子弹顺序表:
	vectorInit(&m->vecBullets);
	m->bulletGerncnt = 0;
}
//销毁
void mainsceneDestory(struct mainscene* m)
{
	heroDestory(m->hero);
	free(m->hero);

	backgroundDestory(m->bk);
	free(m->bk);

	//销毁所有的子弹,检查数组中是否还有子弹:
	for (int i = 0; i < m->vecBullets.size; i++)
	{
		struct bullet* p = (struct bullet*)m->vecBullets.get(&m->vecBullets, i);
		//消除数组中的子弹:
		bulletDestory(p);
		free(p);
	}

	vectorDestroy(&m->vecBullets);

}

4.使用场景(飞机+背景+子弹)的对象:

#define _CRT_SECURE_NO_WARNINGS 1

#include"scene.h"
#include<stdio.h>
#include"gloop.h"
#include<easyx.h>

void gloop(struct scene* s)
{
	//开启批量绘制
	timeBeginPeriod(1);
	BeginBatchDraw();
	while (1)
	{
		cleardevice();

		s->draw(s);
		s->update(s);


		if (s->isQuit(s))
		{
			break;
		}

		Sleep(10);

		//获取鼠标消息:
		//鼠标移动的一个坐标消息:
		ExMessage msg;
		bool isok = peekmessage(&msg, EX_MOUSE);

		//没有鼠标移动不需要控制移动:
		if (isok)
		{
			s->control(s, &msg);
		}
		FlushBatchDraw();
	}

	EndBatchDraw();
	timeEndPeriod(1);
}

5.加入大中小敌人飞机到场景中:

mainscene.h

#define _CRT_SECURE_NO_WARNINGS 1

#include"mainscene.h"
#include"hero.h"
#include<stdlib.h>
#include"bullet.h"
#include<time.h>

#include"enemy0.h"
#include"enemy1.h"
#include"enemy2.h"

//1.场景元素的绘制:
void mainSceneDraw(struct mainscene* s)
{
	//顺序表中有背景和英雄就可以了:
	s->vecElements.clear(&s->vecElements);

	//1.加入bk和hero到顺序表中:
	s->vecElements.append(&s->vecElements, s->bk);
	s->vecElements.append(&s->vecElements, s->hero);

	//3.加入敌人飞机到顺序表:
	for (int i=0;i<s->vecEnemy.size;i++)
	{
		struct enemy* tmp = (struct enemy*)s->vecEnemy.get(&s->vecEnemy, i);
		s->vecElements.append(&s->vecElements, tmp);
	}

	//2.加入子弹到我们的顺序表中:
	for (int i = 0; i < s->vecBullets.size; i++)
	{
		struct bullet* tmp = (struct bullet*)s->vecBullets.get(&s->vecBullets, i);
		s->vecElements.append(&s->vecElements, tmp);
	}

	for (int i = 0; i < s->vecElements.size; i++)
	{
		//获取数据
		struct sprite* tmp = (struct sprite*)(s->vecElements.PData[i]);
		//绘制数据
		tmp->draw(tmp);
	}
}

//2-1子弹数据的初始化:
void generaBullet(struct mainscene* b)
{
	//每一颗子弹进行初始化:
	struct bullet* PBullet = (struct bullet*)malloc(sizeof(struct bullet));
	if (PBullet == NULL)
	{
		perror("malloc file");
		exit(-1);
	}

	bulletInit(PBullet);
	//根据英雄飞机去初始化子弹的位置:
	PBullet->super.x = b->hero->super.x + 32;
	PBullet->super.y = b->hero->super.y - 6;

	//添加到顺序表中:
	b->vecBullets.append(&b->vecBullets, PBullet);
}

//2-2:子弹数据的一个删除
void destorygeneraBullet(struct mainscene* b)
{
	//1.要有数据才可以删除数据
	if (b->vecBullets.size <= 0)
	{
		return;
	}

	//获取头子弹:
	struct bullet* tmp = (struct bullet*)b->vecBullets.get(&b->vecBullets, 0);

	if (tmp->super.y < -14)
	{
		//头删
		b->vecBullets.remove(&b->vecBullets, 0);
		bulletDestory(tmp);
		free(tmp);
	}

}


//3-1:增加1个敌人飞机的函数:
void generateNewEnemy(struct mainscene* s)
{
	srand((unsigned int)time(NULL));
	//规定每一个种类敌人飞机生成的概率:
	int r = rand() % 60;
	struct enemy* PEnemy = NULL;

	if (0 <= r && r < 40)
	{
		struct enemy0* PEnemy0 = (struct enemy0*)malloc(sizeof(struct enemy0));
		if (PEnemy0 == NULL)
		{
			perror("malloc file");
			exit(-1);
		}
		//初始化:
		enemy0Init(PEnemy0);
		PEnemy = (struct enemy*)PEnemy0;
	}
	else if (40 <= r && r < 55)
	{
		struct enemy1* PEnemy1 = (struct enemy1*)malloc(sizeof(struct enemy1));
		if (PEnemy1 == NULL)
		{
			perror("malloc file");
			exit(-1);
		}
		//初始化:
		enemy1Init(PEnemy1);
		PEnemy = (struct enemy*)PEnemy1;
	}
	else if (55 <= r && r < 60)
	{
		struct enemy2* PEnemy2 = (struct enemy2*)malloc(sizeof(struct enemy2));
		if (PEnemy2 == NULL)
		{
			perror("malloc file");
			exit(-1);
		}
		//初始化:
		enemy0Init(PEnemy2);
		PEnemy = (struct enemy*)PEnemy2;
	}

	//水平方向上x的随机生成:
	int m, n;
	m = 20;
	n = 422;
	PEnemy->super.x = rand() % (n - m + 1) + m;

	//根据类型有不同的y值因为三个类型的飞机他们的高是不一样的开始不可以被看到:
	if (PEnemy->enemType == enemType0)
	{
		PEnemy->super.y = -26;
	}
	else if (PEnemy->enemType == enemType1)
	{
		PEnemy->super.y = -59;
	}
	else if (PEnemy->enemType == enemType2)
	{
		PEnemy->super.y = -162;
	}

	//将敌人飞机的指针添加进入数组:
	s->vecEnemy.append(&s->vecEnemy, PEnemy);
}

//3-2:销毁1个敌人飞机的函数:
void destroyInvalidEnemy(struct mainscene* s)
{
	//遍历顺序表看一看那一些需要被销毁
	for(int i=0;i<s->vecEnemy.size;i++)
	{
		//临时变量销毁数据内容
		struct enemy* PEnemy = (struct enemy*)s->vecEnemy.get(&s->vecEnemy, i);

		if (PEnemy->super.y > 750 || PEnemy->status == enemy_destory)
		{
			//从数组中移除:
			s->vecEnemy.remove(&s->vecEnemy,i);
			//元素中开辟的内容:
			PEnemy->destory(PEnemy);
			free(PEnemy);

			//因为remove了所以size--
			i--;
		}
		
	}

}
//2.场景数据的更新:
void mainScenceUpdata(struct mainscene* s)
{
	for (int i = 0; i < s->vecElements.size; i++)
	{
		//获取数据
		struct sprite* tmp = (struct sprite*)(s->vecElements.PData[i]);
		//更新数据
		tmp->updata(tmp);
	}

	//添加敌人飞机:
	int n = rand() % 120;
	if (n == 0)
	{
		//新增加敌人飞机的函数;
		generateNewEnemy(s);
	}
	//销毁无消敌人飞机时时刻刻需要判断的:
	destroyInvalidEnemy(s);


	//添加子弹:
	s->bulletGerncnt++;
	if (s->bulletGerncnt >= 15)
	{
		generaBullet(s);
		s->bulletGerncnt = 0;
	}
	//判断子弹是否可以销毁:
	destorygeneraBullet(s);


	
}
//3.获取鼠标消息
void mainSceneCountrol(struct mainscene* s, ExMessage* msg)
{
	if (msg->message == WM_MOUSEMOVE)
	{
		//把鼠标当前坐标设置为英雄飞机的坐标
		s->hero->super.x = msg->x - 35;
		s->hero->super.y = msg->y - 35;
	}
}

//4.hero飞机的状态判断:
bool mainSceneIsQuit(struct mainscene* s)
{
	if (s->hero->state == hero_destory)
		return true;

	return false;
}


//初始化
void mainsceneInit(struct mainscene* m)
{
	m->super.draw = (void(*)(scene*))mainSceneDraw;
	m->super.update = (void(*)(scene*))mainScenceUpdata;
	m->super.control = (void(*)(scene*,ExMessage*))mainSceneCountrol;
	m->super.isQuit = (bool(*)(scene*))mainSceneIsQuit;

	//初始化背景:
	m->bk = (struct background*)malloc(sizeof(struct background));
	backgroundInit(m->bk);
	//初始化英雄飞机:
	m->hero = (struct hero*)malloc(sizeof(struct hero));
	heroInit(m->hero);

	//初始化场景和飞机的数组:
	vectorInit(&m->vecElements);
	//初始化子弹顺序表:
	vectorInit(&m->vecBullets);
	m->bulletGerncnt = 0;

	//初始化敌人飞机的顺序表:
	vectorInit(&m->vecEnemy);
	m->count = 0;
}
//销毁
void mainsceneDestory(struct mainscene* m)
{
	heroDestory(m->hero);
	free(m->hero);

	backgroundDestory(m->bk);
	free(m->bk);

	//这些销毁方法是
	//1.防止内存泄漏:
	//2.敌人飞机
	//英雄飞机打死销毁,超出屏幕范围被销毁。
	//有一些敌人飞机,在程序结束了,没有出屏幕范围也没有没有射击死就。
	//没有下面的销毁就会产生内存泄漏
	
	//销毁所有的敌人飞机,检查数组中是否还有飞机:
	for (int i = 0; i < m->vecEnemy.size; i++)
	{
		struct enemy* pEnemy = (struct enemy*)m->vecEnemy.get(&m->vecEnemy, i);
		//消除数组中的子弹:
		pEnemy->destory(pEnemy);
		free(pEnemy);
	}
	vectorDestroy(&m->vecBullets);


	//销毁所有的子弹,检查数组中是否还有子弹:
	for (int i = 0; i < m->vecBullets.size; i++)
	{
		struct bullet* p = (struct bullet*)m->vecBullets.get(&m->vecBullets, i);
		//消除数组中的子弹:
		bulletDestory(p);
		free(p);
	}
	vectorDestroy(&m->vecBullets);
}

6.子弹射击到敌人飞机检查请添加图片描述

//4-1:检查子弹射击敌人飞机:
void bulletHitEnemyCheck(struct mainscene* s)
{
	for (int i = 0; i < s->vecBullets.size; i++)
	{
		struct bullet* PBullet = (struct bullet*)
			s->vecBullets.get(&s->vecBullets, i);

		POINT bulletPoint;

		bulletPoint.x = PBullet->super.x + 6 / 2;
		bulletPoint.y = PBullet->super.y;

		for (int j = 0; j < s->vecEnemy.size; j++)
		{
			struct enemy* PEnemy =(struct enemy*)s->vecEnemy.get(&s->vecEnemy, j);

			int width, hight;
			width = PEnemy->super.width;
			hight = PEnemy->super.hight;

			int left, top, right, bottom;
			left = PEnemy->super.x;
			top = PEnemy->super.y;
			right = left + width;
			bottom = top + hight;

			if (bulletPoint.x > left && bulletPoint.x< right &&
				bulletPoint.y>top && bulletPoint.y < bottom)
			{
				if (PEnemy->lift != 0)
				{
					//敌人飞机还没有死,子弹撞击到了飞机子弹应该被销毁
					bulletDestory(PBullet);
					free(PBullet);
					s->vecBullets.remove(&s->vecBullets, i);
					i--;

					PEnemy->hited(PEnemy);
					break;
				}
			}

		}
	}
}

//2.场景数据的更新:
void mainScenceUpdata(struct mainscene* s)
{
	for (int i = 0; i < s->vecElements.size; i++)
	{
		//获取数据
		struct sprite* tmp = (struct sprite*)(s->vecElements.PData[i]);
		//更新数据
		tmp->updata(tmp);
	}

	//添加敌人飞机:
	int n = rand() % 120;
	if (n == 0)
	{
		//新增加敌人飞机的函数;
		generateNewEnemy(s);
	}
	//销毁无消敌人飞机时时刻刻需要判断的:
	destroyInvalidEnemy(s);


	//添加子弹:
	s->bulletGerncnt++;
	if (s->bulletGerncnt >= 15)
	{
		generaBullet(s);
		s->bulletGerncnt = 0;
	}
	//判断子弹是否可以销毁:
	destorygeneraBullet(s);


	//监测子弹是否撞击敌人飞机:
	bulletHitEnemyCheck(s);


	
}

7.子弹碰撞到敌人飞机的爆炸检查:

/4-2:
bool heroHitEnemyChack(struct mainscene* s)
{
	//英雄飞机的矩形区域,减少了碰撞区域所以范围是这样的:
	RECT rectHeror;

	rectHeror.left = s->hero->super.x + 16;
	rectHeror.top = s->hero->super.y + 10;
	rectHeror.right = s->hero->super.x + 16 * 3;
	rectHeror.bottom = s->hero->super.y + 62;

	for (int i = 0; i < s->vecEnemy.size; i++)
	{
		struct enemy* PEnemy = (struct enemy*)
			s->vecEnemy.get(&s->vecEnemy, i);

		int enemyWidth = 0, enemyhight = 0;

		if (PEnemy->status != enemy_normal)
			continue;


		//敌人飞机的矩形区域
		RECT rectEnemy;
		rectEnemy.left = PEnemy->super.x;
		rectEnemy.top = PEnemy->super.y;
		rectEnemy.right = PEnemy->super.x + PEnemy->super.width;
		rectEnemy.bottom = PEnemy->super.y + PEnemy->super.hight;

		//检查两个区域是否重碟
		if (rectHeror.left <= rectEnemy.right
			&& rectHeror.right >= rectEnemy.left
			&& rectHeror.top <= rectEnemy.bottom
			&& rectHeror.bottom >= rectEnemy.top)
		{
			if (s->hero->state== hero_normal0
				|| s->hero->state == hero_normal1)
				return true;
		}

	}
	return false;
}

//2.场景数据的更新:
void mainScenceUpdata(struct mainscene* s)
{
	for (int i = 0; i < s->vecElements.size; i++)
	{
		//获取数据
		struct sprite* tmp = (struct sprite*)(s->vecElements.PData[i]);
		//更新数据
		tmp->updata(tmp);
	}

	//添加敌人飞机:
	int n = rand() % 120;
	if (n == 0)
	{
		//新增加敌人飞机的函数;
		generateNewEnemy(s);
	}
	//销毁无消敌人飞机时时刻刻需要判断的:
	destroyInvalidEnemy(s);


	//添加子弹:
	s->bulletGerncnt++;
	if (s->bulletGerncnt >= 15)
	{
		generaBullet(s);
		s->bulletGerncnt = 0;
	}

	//判断子弹是否可以销毁:
	destorygeneraBullet(s);

	//监测子弹是否撞击敌人飞机:
	bulletHitEnemyCheck(s);

	//监测英雄飞机是否被敌人碰撞:
	bool isHited = heroHitEnemyChack(s);

	if (isHited == true)
	{
		s->hero->lift--;
		s->hero->state = hero_down0;
	}
	

}

8.在游戏场景中加入音乐:

maainscene.h

#include"hero.h"
#include"scene.h"
#include"vector.h"
#include"background.h"
#include<stdbool.h>
#include"music.h"

struct mainscene {
	
	//场景必备:
	struct scene super;
	//飞机
	struct hero* hero;
	//背景
	struct background* bk;
	//元素:背景+飞机
	struct vector vecElements;

	//子弹顺序表:
	struct vector vecBullets;
	int bulletGerncnt;
	//记数器

	//敌人飞机的顺序表:
	struct vector vecEnemy;
	int count;

	//记录玩家得分:
	int mark;

	//音频
	music enemyDownSoundMgr;
	int soundCloseCnt;
};

9.在对应位置播放关闭音乐和添加成绩:

初始化和开始的音乐播放

//初始化
void mainsceneInit(struct mainscene* m)
{
	m->super.draw = (void(*)(scene*))mainSceneDraw;
	m->super.update = (void(*)(scene*))mainScenceUpdata;
	m->super.control = (void(*)(scene*,ExMessage*))mainSceneCountrol;
	m->super.isQuit = (bool(*)(scene*))mainSceneIsQuit;

	//初始化背景:
	m->bk = (struct background*)malloc(sizeof(struct background));
	backgroundInit(m->bk);
	//初始化英雄飞机:
	m->hero = (struct hero*)malloc(sizeof(struct hero));
	heroInit(m->hero);

	//初始化场景和飞机的数组:
	vectorInit(&m->vecElements);
	//初始化子弹顺序表:
	vectorInit(&m->vecBullets);
	m->bulletGerncnt = 0;

	//初始化敌人飞机的顺序表:
	vectorInit(&m->vecEnemy);
	m->count = 0;

	//初始化成绩
	m->mark = 0;

	//初始化音频:

	settextcolor(WHITE);
	settextstyle(30, 0, "微软雅黑");
	setbkmode(TRANSPARENT);

	musicInit(&m->enemyDownSoundMgr, "sounds/enemy_down.wma");
	mciSendString("open sounds/background.wma", NULL, 0, NULL);
	//背景音乐重复播放所以添加一个repeat
	mciSendString("play sounds/background.wma repeat", NULL, 0, NULL);

}

成绩记录打印


//1.场景元素的绘制:
void mainSceneDraw(struct mainscene* s)
{
	//顺序表中有背景和英雄就可以了:
	s->vecElements.clear(&s->vecElements);

	//1.加入bk和hero到顺序表中:
	s->vecElements.append(&s->vecElements, s->bk);
	s->vecElements.append(&s->vecElements, s->hero);

	//3.加入敌人飞机到顺序表:
	for (int i=0;i<s->vecEnemy.size;i++)
	{
		struct enemy* tmp = (struct enemy*)s->vecEnemy.get(&s->vecEnemy, i);
		s->vecElements.append(&s->vecElements, tmp);
	}

	//2.加入子弹到我们的顺序表中:
	for (int i = 0; i < s->vecBullets.size; i++)
	{
		struct bullet* tmp = (struct bullet*)s->vecBullets.get(&s->vecBullets, i);
		s->vecElements.append(&s->vecElements, tmp);
	}

	for (int i = 0; i < s->vecElements.size; i++)
	{
		//获取数据
		struct sprite* tmp = (struct sprite*)(s->vecElements.PData[i]);
		//绘制数据
		tmp->draw(tmp);
	}

	//主场景的左上角加一个成绩记录

	char buff[10];
	sprintf(buff, "得分:%d", s->mark);
	outtextxy(0, 0, buff);

}

敌人飞机毁灭声音

//4-1:检查子弹射击敌人飞机:
void bulletHitEnemyCheck(struct mainscene* s)
{
	for (int i = 0; i < s->vecBullets.size; i++)
	{
		struct bullet* PBullet = (struct bullet*)
			s->vecBullets.get(&s->vecBullets, i);

		POINT bulletPoint;

		bulletPoint.x = PBullet->super.x + 6 / 2;
		bulletPoint.y = PBullet->super.y;

		for (int j = 0; j < s->vecEnemy.size; j++)
		{
			struct enemy* PEnemy =(struct enemy*)s->vecEnemy.get(&s->vecEnemy, j);

			int width, hight;
			width = PEnemy->super.width;
			hight = PEnemy->super.hight;

			int left, top, right, bottom;
			left = PEnemy->super.x;
			top = PEnemy->super.y;
			right = left + width;
			bottom = top + hight;

			if (bulletPoint.x > left && bulletPoint.x< right &&
				bulletPoint.y>top && bulletPoint.y < bottom)
			{
				if (PEnemy->lift != 0)
				{
					//敌人飞机还没有死,子弹撞击到了飞机子弹应该被销毁
					bulletDestory(PBullet);
					free(PBullet);
					s->vecBullets.remove(&s->vecBullets, i);
					i--;

					PEnemy->hited(PEnemy);

					//敌人飞机被打调之后
					if (PEnemy->lift == 0)
					{
						s->enemyDownSoundMgr.play(&s->enemyDownSoundMgr);
					}
					break;
				}
			}

		}
	}
}

英雄飞机毁灭的声音

//2.场景数据的更新:
void mainScenceUpdata(struct mainscene* s)
{
	for (int i = 0; i < s->vecElements.size; i++)
	{
		//获取数据
		struct sprite* tmp = (struct sprite*)(s->vecElements.PData[i]);
		//更新数据
		tmp->updata(tmp);
	}

	//添加敌人飞机:
	int n = rand() % 120;
	if (n == 0)
	{
		//新增加敌人飞机的函数;
		generateNewEnemy(s);
	}
	//销毁无消敌人飞机时时刻刻需要判断的:
	destroyInvalidEnemy(s);


	//添加子弹:
	s->bulletGerncnt++;
	if (s->bulletGerncnt >= 15)
	{
		generaBullet(s);
		s->bulletGerncnt = 0;
	}

	//判断子弹是否可以销毁:
	destorygeneraBullet(s);

	//监测子弹是否撞击敌人飞机:
	bulletHitEnemyCheck(s);

	//监测英雄飞机是否被敌人碰撞:
	bool isHited = heroHitEnemyChack(s);

	if (isHited == true)
	{
		s->hero->lift--;
		s->hero->state = hero_down0;

		mciSendString("open sounds/hero_down.wma", NULL, 0, NULL);
		mciSendString("play sounds/hero_down.wma", NULL, 0, NULL);

	}
	

}

结尾关闭所有音乐和数组销毁

//销毁
void mainsceneDestory(struct mainscene* m)
{

	mciSendString("close sounds/background.wma", NULL, 0, NULL);
	mciSendString("close sounds/hero_down.wma", NULL, 0, NULL);
	musicDestory(&m->enemyDownSoundMgr);


	heroDestory(m->hero);
	free(m->hero);

	backgroundDestory(m->bk);
	free(m->bk);

	//这些销毁方法是
	//1.防止内存泄漏:
	//2.敌人飞机
	//英雄飞机打死销毁,超出屏幕范围被销毁。
	//有一些敌人飞机,在程序结束了,没有出屏幕范围也没有没有射击死就。
	//没有下面的销毁就会产生内存泄漏
	
	//销毁所有的敌人飞机,检查数组中是否还有飞机:
	for (int i = 0; i < m->vecEnemy.size; i++)
	{
		struct enemy* pEnemy = (struct enemy*)m->vecEnemy.get(&m->vecEnemy, i);
		//消除数组中的子弹:
		pEnemy->destory(pEnemy);
		free(pEnemy);
	}
	vectorDestroy(&m->vecBullets);


	//销毁所有的子弹,检查数组中是否还有子弹:
	for (int i = 0; i < m->vecBullets.size; i++)
	{
		struct bullet* p = (struct bullet*)m->vecBullets.get(&m->vecBullets, i);
		//消除数组中的子弹:
		bulletDestory(p);
		free(p);
	}
	vectorDestroy(&m->vecBullets);
}

10.一次游戏结束打印总成绩(并且等待一定的时间回到菜单:)

#include<stdio.h>
#include<easyx.h>
#include"mainscene.h"
#include"gloop.h"
#include"menuscene.h"

int main()
{
	initgraph(422, 750);
	setbkcolor(WHITE);
	cleardevice();

	while (1)
	{
		struct menu me;
		menuInit(&me);
		gloop((struct scene*)&me);
		menudestory(&me);


		struct mainscene ma;
		mainsceneInit(&ma);
		gloop((struct scene*)&ma);
		mainsceneDestory(&ma);

		//游戏结束
		settextcolor(WHITE);
		settextstyle(100, 0, "微软雅黑");

		const char* PStr = "游戏结束";
		RECT r = { 0,200,422,300 };
		drawtext(PStr, &r, DT_CENTER);

		char buff[10];
		sprintf(buff, "得分:%d", ma.mark);
		r = { 0,300,422,400 };
		drawtext(buff, &r, DT_CENTER);

		Sleep(3000);
	}


	closegraph();
	return 0;
}

五.菜单场景:

menuscene.h

#include"scene.h"

struct menu {
	struct scene super;
	//目录图片:
	IMAGE* menu;

	RECT rectStartGame, rectEndGame;
	//表示是否悬停在按钮上
	bool isStartGameHover, isEndGameHover;

	//表示场景是否退出:默认为flase
	bool isQuit;
};

void menuInit(struct menu*);

void menudestory(struct menu*);

menuscene.cpp

#include"menuscene.h"
#include"scene.h"
#include<easyx.h>

void menuDraw(struct menu* m)
{
	putimage(0, 0, m->menu);

	if (m->isStartGameHover == true)
		settextcolor(WHITE);
	else
		settextcolor(BLACK);

	drawtext("开始游戏", &m->rectStartGame, DT_CENTER);

	if (m->isEndGameHover == true)
		settextcolor(WHITE);
	else
		settextcolor(BLACK);

	drawtext("结束游戏", &m->rectEndGame, DT_CENTER);

}

void menuUpdata(struct menu* m)
{

}

void menuSceneControl(struct menu* m, ExMessage* msg)
{
	switch (msg->message)
	{
		//按下了左键
		case WM_LBUTTONDOWN:
		{
			if (m->isEndGameHover == true)
				exit(0);
			if (m->isStartGameHover == true)
				m->isQuit = true;
			break;
		}
		case WM_MOUSEMOVE:
		{
			//判断是否悬停的问题:
			if (msg->x > m->rectStartGame.left &&
				msg->x<m->rectStartGame.right &&
				msg->y>m->rectStartGame.top &&
				msg->y < m->rectStartGame.bottom)
				m->isStartGameHover = true;
			else
				m->isStartGameHover = false;

			if (msg->x > m->rectEndGame.left
				&& msg->x < m->rectEndGame.right
				&& msg->y<m->rectEndGame.bottom
				&& msg->y>m->rectEndGame.top)
				m->isEndGameHover = true;
			else
				m->isEndGameHover = false;
		}

	}
}

bool menuisquit(struct menu* m)
{
	if (m->isQuit)
	{
		return true;
	}
	return false;
}


//初始化对象:
void menuInit(struct menu* m)
{
	m->super.draw = (void (*)(scene*))menuDraw;
	m->super.update = (void (*)(scene*))menuUpdata;
	m->super.control = (void (*)(scene*, ExMessage*))menuSceneControl;
	m->super.isQuit = (bool (*)(scene*))menuisquit;

	m->isQuit = false;

	m->menu=new IMAGE;
	loadimage(m->menu, "img/menu.png");


	//设置开始和结束按钮的矩形区域:
	m->rectStartGame.left = 130;
	m->rectStartGame.top = 430;
	m->rectStartGame.right = 300;
	m->rectStartGame.bottom = 480;

	m->rectEndGame.left = 130;
	m->rectEndGame.top = 540;
	m->rectEndGame.right = 300;
	m->rectEndGame.bottom = 590;


	settextcolor(BLACK);
	settextstyle(50, 0, "微软雅黑");
	setbkmode(TRANSPARENT);
}

//销毁:
void menudestory(struct menu* m)
{
	delete m->menu;
}

今天的分享就到这里了:全部的代码放到gitee的下面的链接中了:
飞机大战小游戏完整代码

请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/940994.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Day5:react函数组件与类组件

「目标」: 持续输出&#xff01;每日分享关于web前端常见知识、面试题、性能优化、新技术等方面的内容。 「主要面向群体&#xff1a;」前端开发工程师&#xff08;初、中、高级&#xff09;、应届、转行、培训、自学等同学 Day4-今日话题 react「函数组件和类组件」的区别&…

查局域网所有占用IP

查局域网所有占用IP 按&#xff1a;winr 出现下面界面&#xff0c;在文本框中输入 cmd 按确定即可出现cmd命令界面 在cmd命令窗口输入你想要ping的网段&#xff0c;下面192.168.20.%i即为你想要ping的网段&#xff0c;%i代表0-255 for /L %i IN (1,1,254) DO ping -w 1 -n 1…

(动态规划) 剑指 Offer 49. 丑数 ——【Leetcode每日一题】

❓剑指 Offer 49. 丑数 难度&#xff1a;中等 我们把只包含质因子 2、3 和 5 的数称作丑数&#xff08;Ugly Number&#xff09;。求按从小到大的顺序的第 n 个丑数。 示例: 输入: n 10 输出: 12 解释: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 是前 10 个丑数。 说明: 1 是丑数。…

2024年新iPad Pro将实现6年来最大的升级

彭博社的Mark Gurman长期以来一直将iPad Pro的下一次重大更新定在2024年&#xff0c;在最新一期的Power On时事通讯中&#xff0c;他详细阐述了一些细节&#xff0c;这些细节将使其成为“自2018年以来该产品的首次重大更新” 尽管Gurman将最近的iPad升级描述为“最近特别小”&…

word6 图文混排

目录 7-1 段落缩进排版7-2 搞定多级列表难题 7-1 段落缩进排版 段落对齐 缩进问题 悬挂缩进&#xff1a;缩进首行以外的段落 段落对齐&#xff1a; 7-2 搞定多级列表难题

k8s 安装 kubernetes安装教程 虚拟机安装k8s centos7安装k8s kuberadmin安装k8s k8s工具安装 k8s安装前配置参数

k8s采用master, node1, node2 。三台虚拟机安装的一主两从&#xff0c;机器已提前安装好docker。下面是机器配置&#xff0c;k8s安装过程&#xff0c;以及出现的问题与解决方法 虚拟机全部采用静态ip, master 30机器, node1 31机器, node2 32机器 机器ip 192.168.164.30 # ma…

【数据结构与算法篇】手撕八大排序算法之快排的非递归实现及递归版本优化(三路划分)

​&#x1f47b;内容专栏&#xff1a; 《数据结构与算法篇》 &#x1f428;本文概括&#xff1a; 利用数据结构栈(Stack)来模拟递归&#xff0c;实现快排的非递归版本&#xff1b;递归版本测试OJ题时&#xff0c;有大量重复元素样例不能通过&#xff0c;导致性能下降&#xff0…

Self-Supervised Learning

Self-Supervised Learning Bert 的数据是 340M parameters 抽象解释&#x1f446; Bert 单个字的预测 把一个字盖住&#xff1a; 1、把一个字替换成特殊字符(MASK)。 2、替换成随机的一个字,进行训练。 next sentence prediction 通过变换两个连起来的句子的顺序&#x…

C. Battle 2023 (ICPC) Jiangxi Provincial Contest -- Official Contest

Problem - C - Codeforces 题目大意&#xff1a;有n堆石子&#xff0c;给出一个数p&#xff0c;A先B后&#xff0c;每个人每次只能取p的幂个石子&#xff08;包括1&#xff09;问A能不能赢 1<n<3e5;1<p<1e18 思路&#xff1a;先递归算出sg函数看看&#xff0c;s…

detour编译问题及导入visual studio

Detours是经过微软认证的一个开源Hook库&#xff0c;Detours在GitHub上&#xff0c;网址为 https://github.com/Microsoft/Detours 注意版本不一样的话也是会出问题的&#xff0c;因为我之前是vs2022的所以之前的detours.lib不能使用&#xff0c;必须用对应版本的x64 Native To…

线性代数的艺术

推荐一本日本网友Kenji Hiranabe写的《线性代数的艺术》。这本书是基于MIT大牛Gilbert Strang教授的《每个人的线性代数》制作的。 虽然《线性代数的艺术》这本书仅仅只有12页的内容&#xff0c;就把线性代数的重点全画完了&#xff0c;清晰明了。 《线性代数的艺术》PDF版本&…

C语言:指针类型的意义

1.指针的类型决定了解引用时访问几个字节 2.指针的类型决定了指针1、-1跳过几个字节 一、指针的类型决定指针解引用时访问几个字节 例如 int 型指针解引用时访问4个字节 char 型指针解引用时访问1个字节 详解代码如下&#xff1a; int b 0x11223344&#xff08;十六进制&…

通过这 5 项 ChatGPT 创新增强您的见解

为什么绝大多数的人还不会使用chatGPT来提高工作效能&#xff1f;根本原因就在还不会循序渐进的发问与chatGPT互动。本文总结了5个独特的chatGPT提示&#xff0c;可以帮助您更好地与Chat GPT进行交流&#xff0c;以获得更清晰的信息、额外的信息和见解。 澄清假设和限制 用5种提…

2023-8-28 n-皇后问题

题目链接&#xff1a;n-皇后问题 第一种搜索顺序 #include <iostream>using namespace std;const int N 20;int n; char g[N][N]; bool row[N], col[N], dg[N], udg[N];void dfs(int x, int y, int s) {if(y n) y 0, x ;if(x n){if(s n){for(int i 0; i < n;…

水源井监控系统整体解决方案

1.1、系统组成水源井远程监控系统主要由监控中心、通信平台、水源井测控终端、现场启动柜设备组成。系统整体结构按功能可划分为采集层、网络层和应用层等三层&#xff0c;水源井测控终端主要实现采集层的功能&#xff0c;数据传输链路主要实现网络层的功能&#xff0c;中心端管…

ModaHub魔搭社区:将图像数据添加至Milvus Cloud向量数据库中

将图像数据添加至向量数据库中 图像分割裁剪完成后,我们就可以将其添加至 Milvus Cloud 向量数据库中了。为了方便上手,本项目中使用了 Milvus Lite 版本,可以在 notebook 中运行 Milvus 实例。接下来,使用 PyMilvus 连接至 Milvus Lite 提供的默认服务器。 这一步骤中,…

python 单向循环(环形)链表

不带头结点的单向循环链表的示意图 循环链表的应用场景【约瑟夫问题】 现假设 n 5&#xff08;一共有 5 个人&#xff09;&#xff0c;k 1&#xff08;从第 1 个人开始报数&#xff09;&#xff0c; m 2&#xff08;数 2 下&#xff09;&#xff0c;则出队编号的序列为&…

文件上传漏洞之条件竞争

这里拿upload-labs的第18关做演示 首先先看代码 $is_upload false; $msg null;if(isset($_POST[submit])){$ext_arr array(jpg,png,gif);$file_name $_FILES[upload_file][name];$temp_file $_FILES[upload_file][tmp_name];$file_ext substr($file_name,strrpos($file_…

如何编译打包OpenSSH 9.4并实现批量升级

1 介绍 openssh 9.4版本已于8月10号发布&#xff0c;安全团队又催着要赶紧升级环境里的ssh版本&#xff0c;本文主要介绍Centos5、Centos6、Centos7下openssh 9.4源码编译rpm包以及批量升级服务器openssh版本的方法。关注公众号后台回复ssh可获取本文相关源码文件。 https://w…