大家好,我是作者:隐匿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.libIMAGE 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;
}