用C语言写一个简单的飞机大战游戏(用到easyx图形库)

学习内容:1.背景的运动

                  2.飞机爆炸效果

                  3.透明贴图工具

目录

一、需要用到的头文件、全局变量和一些函数、结构体

二、数据初始化以及图片处理

三、主体

四、物体碰撞

五、游戏运行

六、透明贴图工具和定时器


 

一、需要用到的头文件、全局变量和一些函数、结构体

#include<graphics.h>
#include<stdio.h>
#include<easyx.h>
#include<time.h>
#include<stdlib.h>
#include<math.h>
#include<Windows.h>
#include"tool.h"
#pragma comment(lib,"winmm.lib")

#define WIDTH 480
#define HIGHT 700


IMAGE img_bk[2];//背景图
IMAGE img_myplane[2];//玩家飞机
IMAGE img_bullet;//子弹
IMAGE img_enemyplane;//敌机
IMAGE img_enemyboom[4];//敌机爆炸

int bkY[2] = { -700,0 };//两张背景位置
int score = 0;//得分
int enemy_num = 4;//敌机数量
int enemy_add = 0;//敌机需要增加数

//坐标结构体
struct Point
{
	int x;
	int y;
};

//玩家飞机结构坐标,速度,是否存在
struct Plane  
{
	int px;
	int py;
	int speed;
	int frame;//用于切换玩家飞机图片
	bool exis;
}gamer;

//子弹结构体包括坐标和是否存在(可自行添加子弹种类,速度,方向等属性)
typedef struct Bullet
{
	int x;
	int y;
	bool exis;
	Bullet* next;
}mybullet;

mybullet* one_mybullet;

//敌机结构体(可自行添加其他类飞机,boss等)
typedef struct Enemy
{
	int posx;//坐标
	int posy;
	int boom;//爆炸图片帧数
	//int type;//飞机类型
	bool exis;//是否存活
	Enemy* next;
}enemy;

enemy* one_enemy;

void loadImage();                                     //加载图片
void InitPlayer(Plane* pthis, int x, int y);          //初始玩家飞机
void DrawImg();                                       //绘制图片
void DrawPlayer(Plane* pthis);                        //绘制玩家飞机
void PlayerMove();                                    //玩家飞机运动
void RunBk();                                         //背景运动
void CreateBullet();                                  //创建子弹
void AddMybullet();                                   //增加子弹并初始化
void MybulletMove();                                  //子弹移动
void CreatEnemy();                                    //创建敌机
void AddEnemy();                                      //增加敌机并初始化
void EnemyMove();                                     //敌机移动
void HitEnemy();                                      //击中敌机
void LoadBoom();                                      //加载爆炸图片
void AnimalBoom(IMAGE *picture, Enemy* pthis)         //飞机爆炸效果
bool overlapationa(enemy* pthis);                     //判断是否飞机与飞机重叠
bool overlapationb(enemy* pthis);                     //判断是否子弹与飞机重叠
bool collisiona(enemy* e1, enemy* e2);                //判断飞机与飞机是否碰撞
bool collisionb(mybullet* b, enemy* e);               //判断飞机与子弹是否碰撞

二、数据初始化以及图片处理

//初始化数据
void InitData()
{
	mciSendString("open music/bgm1.mp3 alias bkmusic", NULL, 0, NULL);
	mciSendString("play bkmusic repeat", NULL, 0, NULL);

	initgraph(WIDTH, HIGHT,SHOWCONSOLE);//图形窗口
	InitPlayer(&gamer, (getwidth() - img_myplane->getwidth()) / 2, getheight() / 2 + img_myplane->getheight());
    CreateBullet();
	CreatEnemy();
	loadImage();
		
}

//加载图片资源
void loadImage()
{

	loadimage(img_bk + 0, "images/background1.png");//加载背景图片
	loadimage(img_bk + 1, "images/background2.png");//加载背景图片
	loadimage(img_myplane + 0, "images/me1.png");//加载玩家飞机
	loadimage(img_myplane + 1, "images/me2.png");//加载玩家飞机
	loadimage(&img_bullet, "images/bullet1.png");//加载玩家子弹
	loadimage(&img_enemyplane, "images/enemy1.png");//加载敌机图片

	LoadBoom();
	

}

//加载敌机爆炸效果(可以给多个飞机做接口,只演示一种飞机爆炸)
void LoadBoom()
{
	for (int i = 0; i <= 3; i++)
	{
		char fileName[30] = {0};
		sprintf(fileName, "images/enemy1_down%d.png", i);
		loadimage(&img_enemyboom[i], fileName);
	}
}

//敌机爆炸效果(避免使用循环语句、会出现卡顿现象)
void AnimalBoom(IMAGE *picture, Enemy* pthis)
{
	if (pthis->exis == false && timer(20, 3))//控制帧率
	{
		drawImg(pthis->posx, pthis->posy, &picture[pthis->boom] );
		if (pthis->boom == 3)//当三张爆炸图片全部显示完之后,归零
		{
			pthis->boom = 0;
			pthis->exis = true;
            //当创建的敌机与其他敌机重叠时,重新创建,直至不重合
			do
			{
				pthis->posx = rand() % (getheight() / 2);
				pthis->posy = -img_enemyplane.getheight();
			} while ( overlapationa(pthis));
		}
		else
		{
			pthis->boom++;//用于切换下一张图片
		}
	}
}

//让背景连续滚动(用两张上下连接的背景图,循环运动)
void RunBk()
{
	putimage(0, bkY[0], &img_bk[0]);
	putimage(0, bkY[1], &img_bk[1]);//打印出背景图片

	if (timer(50, 1))
	{
		bkY[0] ++;
		bkY[1] ++;
		if (bkY[0] >= 700)
		{
			bkY[0] = -700;
		}
		else if (bkY[1] >= 700)
		{
			bkY[1] = -700;
		}
	}
}

//绘制图片
void DrawImg()
{
	RunBk();//背景滚动

	DrawPlayer(&gamer);//打印玩家飞机图片

	//打印子弹
	mybullet* bt = one_mybullet->next;
	while (bt != NULL&&bt->exis == true)
	{
		drawImg(bt->x, bt->y, &img_bullet);
		//printf("%d    %d\n", bt->x, bt->y);
		bt = bt->next;
	}

	//打印敌机
	enemy* et = one_enemy->next;
	while (et != NULL)
	{
		if (et->exis == true)//飞机不存在时打印爆炸图片
		{
				drawImg(et->posx, et->posy, &img_enemyplane);
		}
		else
		{
					AnimalBoom(img_enemyboom, et);
		}
		et=et->next;
	}

    //显示得分
	setcolor(BLACK);
	settextstyle(25, 0, "黑体");
	TCHAR s[5];
	_stprintf(s,_T("%d"),score);
	outtextxy(20, 20, s);
	setbkmode(0);
}

三、主体

玩家、子弹和敌机的初始化,增加数量和运动等

//飞机初始化
void InitPlayer(Plane* pthis,int x,int y)
{
	pthis->px = x;
	pthis->py = y;
	pthis->exis = true;
	pthis->frame = 0;
}

//绘制玩家飞机,(让玩家飞机有运动效果)
void DrawPlayer(Plane* pthis)
{
	drawImg(pthis->px, pthis->py, img_myplane + pthis->frame);//打印玩家飞机
	pthis->frame = (pthis->frame + 1) % 2;
}
//玩家飞机移动
void PlayerMove()//用鼠标移动玩家飞机
{
	int startclock = clock();
	MOUSEMSG m;//鼠标结构体
	while (MouseHit())
	{
		m = GetMouseMsg();
		if (m.uMsg == WM_MOUSEMOVE)
		{
				gamer.px = m.x - img_myplane->getwidth() / 2;
				gamer.py = m.y - img_myplane->getheight() / 2;
		}
	}
	if (timer(200,0) )
	{
		AddMybullet();
	}
}
//创建玩家飞机子弹
void CreateBullet()
{
	one_mybullet = (mybullet*)malloc(sizeof(mybullet));
	if (one_mybullet == NULL)
	{
		return;
	}
	else
	{
		one_mybullet->next = NULL;
	}
}
//加载子弹
void AddMybullet()
{
	mybullet* pnew = (mybullet*)malloc(sizeof(mybullet));
	if (pnew == NULL)
	{
		return;
	}
	else
	{
		pnew->next = NULL;
		pnew->x = gamer.px + 51;
		pnew->y = gamer.py ;
		pnew->exis = true;
		pnew->next = one_mybullet->next;
		one_mybullet->next = pnew;
	}
}
//让玩家子弹移动
void MybulletMove()
{
	mybullet* P1 = one_mybullet->next;
	mybullet* P2 = one_mybullet;
	for (; P1 != NULL; P1 = P1->next)
	{
		if (P1->y <= 0 || P1->exis == false)//当子弹越界或者死亡时,释放掉子弹
		{
			P2->next = P1->next;
			free(P1);
			return;
		}
		else
		{
			P1->y -= 9;
		}
		P2 = P1;
	}
}
//创建敌机
void CreatEnemy()
{
	one_enemy = (enemy*)malloc(sizeof(enemy));
	if (one_enemy == NULL)
	{
		return;
	}
	one_enemy->next = NULL;
}
增加敌机并初始化
void AddEnemy()
{
	//srand((unsigned int)time(NULL));
	enemy* ep= (enemy*)malloc(sizeof(enemy));
	if (ep == NULL)
	{
		return;
	}
	ep->next = NULL;
	ep->exis = true;
	ep->boom = 0;

	ep->next = one_enemy->next;
	one_enemy->next = ep;
	do
	{
		ep->posx = rand() % (getheight() / 2);
		ep->posy = -img_enemyplane.getheight() / 2;
	} while (ep->next != NULL &&overlapationa(ep));//创建的飞机不与其他飞机重叠,否则重新生成
}
// 敌机移动
void EnemyMove()
{
	srand((unsigned int)time(NULL));
	enemy* pt = one_enemy->next;
	while (pt)
	{
		if (pt->posy >= getheight())
		{
			do
			{
				pt->posx = rand() % (getheight() / 2);
				pt->posy = -img_enemyplane.getheight();
			} while (overlapationa(pt));
		}
		else
		{
			pt->posy += 2;
		}
		pt = pt->next;
	}
}

四、物体碰撞

//击中敌机
void HitEnemy()
{
	enemy* e = NULL;
	mybullet* b = NULL;

	e = one_enemy->next;
	while (e != NULL)
	{
		if (e->exis == false)
		{
			e = e->next;
			continue;
		}
		b = one_mybullet->next;
		while (b != NULL)
		{
			
			if (b->exis == true && collisionb(b, e))
			{
					score++;
					e->exis = false;
					b->exis = false;
			}
			else
			{
				b = b->next;
				continue;
			}
				
			b = b->next;
		}
		e = e->next;
	}
}

//用碰撞物体的四个点的任意点判断是否在被碰撞物范围内
//判断飞机与飞机是否碰撞
bool collisiona(enemy* e1,enemy* e2 )
{
	struct Point ap[4] =
	{
		{e1->posx,e1->posy},
		{e1->posx,e1->posy+img_enemyplane.getheight()},
		{e1->posx+img_enemyplane.getwidth(),e1->posy},
		{ e1->posx + img_enemyplane.getwidth() ,e1->posy + img_enemyplane.getheight() }
	};

	for (int i = 0; i < 4; i++)
	{
		if (ap[i].x >= e2->posx&&ap[i].x <= e2->posx + img_enemyplane.getwidth() &&
			ap[i].y >= e2->posy&&ap[i].y <= e2->posy + img_enemyplane.getwidth())
		{
			return true;
		}	
	}
	return false;
}
//判断子弹与飞机是否碰撞
bool collisionb(mybullet* b, enemy* e)
{
	const struct Point ap[4] =
	{
		{ b->x ,b->y },
		{ b->x,b->y + img_bullet.getheight() },
		{ b->x + img_bullet.getwidth(),b->y },
		{ b->x + img_bullet.getwidth() ,b->y + img_bullet.getheight() }
	};

	for (int i = 0; i < 4; i++)
	{
		if (ap[i].x >= e->posx&&ap[i].x <= e->posx + img_enemyplane.getwidth() &&
			ap[i].y >= e->posy&&ap[i].y <= e->posy + img_enemyplane.getwidth()) 
		{
			return true;
		}
	}
	return false;
}
//判断飞机与飞机是否重叠(避免生成飞机堆叠)
bool overlapationa(enemy* pthis)
{
	enemy* a = NULL;
	a = one_enemy->next;
	while (a != NULL)
	{
		if (pthis == a || a->exis == false)
		{
			a = a->next;
			continue;
		}
		if (collisiona(pthis, a))
		{
			return true;
		}
		a = a->next;
	}
	return false;
}

bool overlapationb(enemy* pthis)
{
	mybullet* a = NULL;
	a = one_mybullet->next;
	while (a != NULL)
	{
		if (collisionb(a, pthis))
		{
			return true;
		}
		a = a->next;
	}
	return false;
}

五、游戏运行

//运行游戏
void RunGame()
{
	BeginBatchDraw();//防止闪屏
	
	if (enemy_add <= enemy_num)//可以设计关卡来增加敌机数量
	{
		AddEnemy();
		enemy_add++;
	}
	DrawImg();
	PlayerMove();
	MybulletMove();
	HitEnemy();
	EnemyMove();
	
	int startTime = clock();
	int frameTime = clock() - startTime;
	if (1000 / 60 - frameTime > 0)
	{
		Sleep(1000 / 30 - frameTime);//控制运行速度
	}
	EndBatchDraw();//结束绘制
}
//====================================== 主程序===============================
//主程序
int main()
{
	InitData();
	
	while (true)
	{
		
		RunGame();
		
	}
	getchar();
	closegraph();
	return 0;
}

六、透明贴图工具和定时器

drawImg()用于贴无背景图片与putimage()相似

#pragma once
#include<easyx.h>
 
void drawImg(int x, int y, IMAGE *src);
void drawImg(int x, int y,int dstw, int dstH, IMAGE *src, int srcX, int srcY);


void drawImg(int x, int y, IMAGE *src)
{
	DWORD* pwin = GetImageBuffer();
	DWORD* psrc = GetImageBuffer(src);
	int win_w = getwidth();
	int win_h = getheight();
	int src_w = src->getwidth();
	int src_h = src->getheight();

	int real_w = (x + src_w > win_w) ? win_w - x : src_w;
	int real_h = (y + src_h > win_h) ? win_h - y: src_h;
	if (x < 0) { psrc += -x;           real_w -= -x; x = 0; }
	if (y < 0) { psrc += (src_w*-y);   real_h -= -y; y = 0; }


	pwin +=(win_w*y + x);


	for (int iy = 0; iy < real_h; iy++)
	{
		for (int ix = 0; ix < real_w; ix++)
		{
			byte a = (byte)(psrc[ix] >> 24);
			if (a > 100)
			{
				pwin[ix] = psrc[ix];
			}
		}

		pwin += win_w;
		psrc += src_w;
	}
}

void drawImg(int x, int y, int dstW, int dstH, IMAGE* src, int srcX, int srcY)
{

	DWORD* pwin = GetImageBuffer();
	DWORD* psrc = GetImageBuffer(src);
	int win_w = getwidth();
	int win_h = getheight();
	int src_w = src->getwidth();
	int src_h = src->getheight();

	int real_w = (x + dstW> win_w) ? win_w - x : dstW;
	int real_h = (y + dstH > win_h) ? win_h - y : dstH;
	if (x < 0) { psrc += -x;          real_w -= -x; x = 0; }
	if (y < 0) { psrc += (dstW*-y);   real_h -= -y; y = 0; }


	pwin += (win_w*y + x);

	for (int iy = 0; iy < real_h; iy++)
	{
		for (int ix = 0; ix < real_w; ix++)
		{
			byte a = (byte)(psrc[ix + srcX + srcY*src_w] >> 24);
			if (a > 100)
			{
				pwin[ix] = psrc[ix + srcX + srcY*src_w];
			}
		}

		pwin += win_w;
		psrc += src_w;

	}
}

//定时器
bool timer(int ms, int id)
{
	static int start[5];
	int end = clock();
	if (end - start[id] >= ms)
	{
		start[id] = end;
		return true;
	}
	return false;
}

总结:实现的内容比较简单,冗余,仅用于学习参考,有兴趣的可以自行添加更多功能,多动手才能有更多的进步哟。

素材:链接:https://pan.baidu.com/s/1XDbXx3C83kyyzkQZL3mmiQ 
提取码:65qv

  • 28
    点赞
  • 167
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: 好的,我会尽力回答您的问题。关于使用C语言easyX图形库五子棋游戏,可以按照以下步骤来实现: 1. 首先,您需要下载并安装easyX图形库,以便在C语言中使用图形界面。在安装完成后,您需要包含easyX头文件并链接easyX库文件。 2. 然后,您需要创建一个窗口并初始化easyX图形库。可以使用initgraph函数来完成这个任务。您可以指定窗口的大小、标题等参数。 3. 接着,您需要在窗口中绘制五子棋棋盘。可以使用line函数来绘制棋盘的线条。您还可以使用circle函数在棋盘上绘制棋子。 4. 在绘制完棋盘后,您需要编逻辑代码来处理游戏规则。可以使用一个二维数组来表示棋盘上的棋子状态。当玩家下棋时,您需要判断当前位置是否为空,如果为空则将棋子放置在该位置。在下完棋子后,您还需要判断是否出现五个连续的棋子,以决定胜负。 5. 最后,您需要实现游戏的交互界面。可以使用鼠标点击事件来控制玩家下棋。在玩家下完棋后,您需要切换到另一个玩家,并等待其下棋。 以上是使用C语言easyX图形库五子棋游戏的基本步骤。希望能对您有所帮助。 ### 回答2: 使用C语言五子棋游戏需要使用EasyX图形库。首先,我们需要在EasyX中建立一个窗口,用于显示游戏界面。接下来,我们需要定义一个二维数组来表示棋盘,并在窗口中将其显示出来。 接着,我们可以定义一些全局变量,如棋盘大小、落子的颜色、上一个落子位置等等。这些变量将在游戏过程中使用。 在游戏过程中,我们需要捕捉用户的鼠标点击事件,以确定落子的位置。当用户点击某个位置时,我们需要判断该位置是否为空,如果为空,则将该位置标记为当前落子的颜色,并在棋盘上显示出来。 同时,我们需要编判断胜利的函数。在每次落子后,我们需要判断当前落子的颜色在水平、垂直、对角线方向上是否形成了五子连珠。如果存在五子连珠,游戏结束,并显示胜利信息。 此外,我们还可以添加悔棋、重新开始等功能,以增强游戏的可玩性。 最后,在游戏结束后,我们需要释放图形资源,并提醒用户是否重新开始游戏。 综上所述,使用C语言五子棋游戏,结合EasyX图形库,可以实现一个简单的五子棋游戏,增加了图形化的界面和用户交互性,提升了用户体验。 ### 回答3: 使用C语言五子棋游戏,并使用EasyX图形库,可以在Windows平台上进行图形化显示和交互。下面以简单的方式介绍如何实现: 1. 准备工作:首先需要下载安装EasyX图形库,并将相关头文件和库文件配置到C语言编译环境中。 2. 创建界面:使用EasyX的绘图函数,绘制游戏界面,包括棋盘、棋子、背景等元素。 3. 实现游戏逻辑:定义一个二维数组作为棋盘,用来存储棋子的位置。使用两个整型变量记录当前轮到哪一方下棋,以及判断游戏是否结束。通过鼠标事件监听鼠标点击的位置,根据当前轮和点击的位置在棋盘数组上落子。每当有棋子落下后,检查是否五连珠,如果有则游戏结束,并显示获胜方信息。 4. 实现AI对战:可以添加一个简单的AI算法,使得人机对战成为可能。AI算法可以根据当前棋盘的情况,计算出最佳下棋位置。例如,可以采用极大极小搜索算法,评估每个可能的下棋位置的得分,并选择得分最高的位置进行下棋。 5. 完善交互功能:可以添加悔棋、重新开始、退出游戏等功能,以提升游戏的体验。 总之,通过C语言EasyX图形库的组合,我们可以实现一个简单但功能完备的五子棋游戏。这个游戏将具有图形化的界面,可以与人机对战,具备基本的游戏功能和操作。通过添加一些额外的功能,能够实现更好的用户体验和更高难度的游戏对战。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值