飞机大战
- 一.飞机大战的基本窗体:
- 二.飞机大战的主要战斗场景元素:
- 一.透明图片:
- 二.精灵对象:
- 三.主游戏场景的元素:
- 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的下面的链接中了:
飞机大战小游戏完整代码