低配版本的雷霆战机,敌机无法发射子弹
在这个游戏中我们能学到什么知识呢?
- 背景的循环原理
- 不一样的增加链表结点的方法
- 链表结点的删除
首先我们要准备一点素材,没有素材的小伙伴,可以私聊我 ~
效果如下所示:
雷霆游戏C语言实现
代码如下所示:
#include <graphics.h> //图形界面库
#include <conio.h> //标准输入输出头文件
#include <mmsystem.h> //音乐头文件
#include <math.h> //数学头文件
#include <stdio.h>
#include <time.h> //时间头文件
#pragma comment(lib,"winmm") //音乐库文件
#define WIDTH 480 //宏定义 控制界面大小
#define HEIGHT 640
IMAGE img_background, img_myplane, img_bullet, img_enemyplane; //定义图像对象
char ch; //接收键盘上按下的字符
int bj_y; //用于移动背景图片
DWORD t1, tt1; //移动背景
DWORD t2, tt2, t3, tt3; //生成子弹和敌机
DWORD t4, tt4; //打印子弹和敌机
//结点 敌机 子弹
typedef struct Node
{
int x; //坐标
int y;
struct Node* pNext;
}NODE;
NODE mine; //我的飞机
NODE* pBullet = NULL; //我的子弹
NODE* pEnemy = NULL; //敌机
void Welcome(); //欢迎界面
void InitGame(); //初始化游戏
void RunGame(); //开始游戏
void MovePlane(); //移动飞机
void CreateList(); //创建链表
void CreateBulletEnemy(int); //创建子弹和敌机 增加结点
void JudgeGame(); //判断游戏
int main()
{
Welcome();
InitGame();
BeginBatchDraw(); //开始批量绘图
while (1)
{
RunGame();
FlushBatchDraw(); //结束批量绘图
}
return 0;
}
void Welcome()
{
SetConsoleTitle("Thunder__Fighter(低级版) 作者:花里胡哨D 梦"); //设置窗口名称
printf("欢迎来到飞机大战游戏界面!\n\n");
printf("控制:↑ ↓ → ←\n\n");
printf("游戏低级的原因:游戏未设置敌方子弹 →.→\n\n");
printf("\t\t注意不要碰到敌机,否则游戏将会结束!!!\n\n\n\n");
printf("按任意键继续...");
getch();
}
void InitGame()
{
initgraph(WIDTH, HEIGHT); //游戏界面大小
srand((unsigned)time(0));
loadimage(&img_background, "background.bmp", WIDTH, HEIGHT); //加载图片
loadimage(&img_myplane, "myplane.bmp");
loadimage(&img_bullet, "bullet.bmp");
loadimage(&img_enemyplane, "enemyplane.bmp");
mciSendString("open bj.mp3", 0, 0, 0); //背景音乐
mciSendString("play bj.mp3 repeat", 0, 0, 0);
mine.x = WIDTH / 2 - 37, mine.y = HEIGHT - 200; //飞机的初始位置
mine.pNext = NULL;
t1 = GetTickCount(); //用于获取系统时间
t2 = GetTickCount();
t3 = GetTickCount();
t4 = GetTickCount();
CreateList(); //创建链表
}
void RunGame()
{
tt1 = GetTickCount(); //背景
tt2 = GetTickCount(); //我方子弹
tt3 = GetTickCount(); //敌机
tt4 = GetTickCount(); //打印子弹和敌机
if (tt1 - t1 >= 10) //动态背景
{
if (bj_y >= HEIGHT)
bj_y = 0;
putimage(0, -HEIGHT + bj_y, &img_background); //用两张图片形成循环
putimage(0, bj_y, &img_background);
bj_y += 1;
t1 = tt1;
}
if (tt2 - t2 > 100) //100个毫秒 生成子弹
{
CreateBulletEnemy(0);
t2 = tt2;
}
if (tt3 - t3 > 1000) //1000个毫秒 生成敌机
{
CreateBulletEnemy(1);
t3 = tt3;
}
NODE* p; //用于打印子弹、飞机
if (tt4 - t4 > 10)
{
p = pBullet->pNext;
while (p != NULL) //打印子弹
{
putimage(p->x, p->y, 60, 25, &img_bullet, 60, 0, SRCAND);
putimage(p->x, p->y, 60, 25, &img_bullet, 0, 0, SRCPAINT);
p->y -= 5;
p = p->pNext;
}
p = pEnemy->pNext;
while (p != NULL) //打印敌机
{
putimage(p->x, p->y, 50, 34, &img_enemyplane, 0, 0, SRCAND);
putimage(p->x, p->y, 50, 34, &img_enemyplane, 50, 0, SRCPAINT);
p->y += 2;
p = p->pNext;
}
t4 = tt4;
}
if (kbhit()) //判断是否从键盘上按下字符
MovePlane();
JudgeGame();
putimage(mine.x, mine.y, 75, 45, &img_myplane, 0, 15, SRCAND); //自己的飞机
putimage(mine.x, mine.y, 75, 45, &img_myplane, 75, 15, SRCPAINT);
}
void MovePlane()
{
ch = getch();
switch (ch) //改变飞机的位置
{
case 72:
if (mine.y > 0)
mine.y -= 15;
break;
case 75:
if (mine.x > 0)
mine.x -= 15;
break;
case 77:
if (mine.x < WIDTH - 75)
mine.x += 15;
break;
case 80:
if (mine.y < HEIGHT - 75)
mine.y += 15;
break;
}
}
void CreateList()
{
pBullet = (NODE*)malloc(sizeof(NODE)); //为结构体变量开辟一段空间
pBullet->pNext = NULL;
pEnemy = (NODE*)malloc(sizeof(NODE));
pEnemy->pNext = NULL;
}
void CreateBulletEnemy(int flag) //游戏逻辑部分
{
NODE* pNew = (NODE*)malloc(sizeof(NODE));
if (flag == 0) //子弹
{
pNew->x = mine.x + 7;// 子弹宽度6 高度8
pNew->y = mine.y - 25;
pNew->pNext = pBullet->pNext;
pBullet->pNext = pNew;
}
else if (flag == 1) //敌机
{
pNew->x = rand() % WIDTH;
pNew->y = 0;
pNew->pNext = pEnemy->pNext;
pEnemy->pNext = pNew;
}
}
void JudgeGame()
{
//1 子弹和敌机 到达边界要释放
NODE* pLastBullet = pBullet; //上一个的结点
NODE* pPreBullet = pBullet->pNext; //当前的结点
NODE* pLastEnemy = pEnemy;
NODE* pPreEnemy = pEnemy->pNext;
while (pPreBullet != NULL)
{
if (pPreBullet->y < 0) //找到链表的最后一个
{
pLastBullet->pNext = NULL;
free(pPreBullet);
break;
}
pLastBullet = pLastBullet->pNext;
pPreBullet = pPreBullet->pNext;
}
while (pPreEnemy != NULL)
{
if (pPreEnemy->y > HEIGHT) //找到链表的最后一个
{
pLastEnemy->pNext = NULL;
free(pPreEnemy);
break;
}
pLastEnemy = pLastEnemy->pNext;
pPreEnemy = pPreEnemy->pNext;
}
//2 子弹碰到敌机 子弹和敌机被释放
pLastBullet = pBullet; //每一颗子弹都要遍历一次敌机
pPreBullet = pBullet->pNext;
while (pPreBullet != NULL)
{
pLastEnemy = pEnemy;
pPreEnemy = pEnemy->pNext;
while (pPreEnemy != NULL)
{
if (abs(pPreBullet->x - pPreEnemy->x) < 50 && pPreBullet->y - pPreEnemy->y < 35 && pPreBullet->y - pPreEnemy->y > 0)
{
pLastBullet->pNext = pPreBullet->pNext;
free(pPreBullet);
pLastEnemy->pNext = pPreEnemy->pNext;
free(pPreEnemy);
pLastBullet = pBullet; //子弹回到第一个!!! 原因:第一个已经被释放掉了 不能跳着来
pPreBullet = pBullet->pNext;
break;
}
else
{
pLastEnemy = pLastEnemy->pNext;
pPreEnemy = pPreEnemy->pNext;
}
}
pLastBullet = pLastBullet->pNext;
pPreBullet = pPreBullet->pNext;
}
//3 判断游戏是否结束
pPreEnemy = pEnemy->pNext;
while (pPreEnemy != NULL)
{
if (abs((mine.x + 37) - (pPreEnemy->x + 25)) < 62 && abs(mine.y - pPreEnemy->y) < 20)
{
MessageBox(NULL, " 游戏结束", "PlaneGame", MB_OK);
exit(0);
}
pPreEnemy = pPreEnemy->pNext;
}
}