栏目分类:
子分类:
返回
文库吧用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
文库吧 > IT > 软件开发 > 后端开发 > C/C++/C#

用C语言写一个简单的球球大作战游戏(图形界面用easyx)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

用C语言写一个简单的球球大作战游戏(图形界面用easyx)

 1. 引用与声明

1.1 此处包含需要用到的头文件,一些声明和定义 声明一个结构体可以让食物,玩家和ai玩家用,避免重复的定义。

#include
#include
#include
#include
#include
#pragma comment(lib,"Winmm.lib")

#define WIDTH 1024 //窗口宽度
#define HEIGHT 640//窗口高度
#define AI_NUM 10 //ai数量

const int Gridsize = 10; //格子宽度
int food_num = 100;//食物数量
int ai_num = 10;//ai玩家数量   

//给ai玩家起名字
const char* names[AI_NUM] = { "南夕子","马斯克","地狱烈火","非常可乐","今夜无眠","十大恶人","有你真好","世界和平",
								  "马赛克","统一" };

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

//精灵结构体包括坐标,半径,颜色等
 struct Sprite
{
	double x;//坐标
	double y;
	double r;//半径
	DWORD color;//颜色
	char name[20];//名字
	bool exist;//判断是否存在

	Sprite* food_index;//目标食物
	Sprite* next;//结点指针
};

//定义一个玩家结构体
Sprite player;

//定义一个食物
Sprite* one_food;

//定义ai玩家
Sprite*one_aiplayer;

//调用函数
void InitSprite(Sprite* spr, double x, double y,double r, const char* name = "Sprite");
void DrawPlayer(Sprite* spr, bool showName = true);
void AddFood();
void  CreatFood();
void CreatAIplayer();
void AddAIplayer(int num);
void sort();
void ranking();
int game_menu();
 2.主体函数

2.1 游戏画面初始化和绘制 画出食物,玩家和ai玩家

//初始化数据
void InitData()
{
	srand(unsigned int (time(NULL)));
	
	setbkcolor(WHITE);
	cleardevice();//清空原来颜色
	
	mciSendString("open resource/bk.mp3",NULL,0,NULL);
	mciSendString("play resource/bk.mp3 repeat", NULL, 0, NULL);

	InitSprite(&player, rand() % WIDTH, rand() % HEIGHT,10, "必胜客");//初始化玩家

	CreatFood();//创建食物头指针

	//将所有食物加载出来
	for (int i = 0; i < food_num; i++)
	{
		AddFood();
	}

	CreatAIplayer();

	for (int i = 0; i < ai_num; i++)
	{
		AddAIplayer(i);
	}
}

//绘制图画
void DrawImg()
{
	//画坐标格子
	setlinecolor(RGB(100, 250, 100));//设置格子颜色
	for (int i = 0; i <= WIDTH / Gridsize; i++)//画纵坐标线段
	{
		line(i*Gridsize, 0, i*Gridsize, HEIGHT);
	}
	for (int k = 0; k <= HEIGHT/Gridsize; k++)//画横坐标线段
	{
		line(0, k*Gridsize, WIDTH, k*Gridsize);
	}

	
	DrawPlayer(&player);//绘制玩家

	//绘制食物
	Sprite* fp;
	fp = one_food->next;
	while (fp != NULL)
	{
		DrawPlayer(fp,false);
		fp = fp->next;
	}

	//绘制ai玩家
	Sprite* tp;
	tp = one_aiplayer->next;
	while (tp != NULL)
	{
		DrawPlayer(tp, true);
		tp = tp->next;
	}
}

//操作结构体函数(玩家,食物,ai玩家都适用)
void InitSprite(Sprite* spr, double x, double y,double r, const char* name )
{
	spr->x = x;
	spr->y = y;
	spr->r = r;
	spr->color = RGB(rand()% 256, rand()% 256, rand()% 256);
	spr->exist = true;
	strcpy(spr->name, name);
	spr->food_index = NULL;
}

 2.2 创建角色 创建玩家,对玩家的按键处理来控制方向移动,用链表来创建食物以及ai玩家,当食物被吃时重新随机刷新。

 

void DrawPlayer(Sprite* spr, bool showName )
{
	if (spr->exist)
	{
		//绘制图形
		setfillcolor(spr->color);//填充颜色
		solidcircle(spr->x, spr->y, spr->r);//绘制图形位置

		if (showName)//判断是否需要名字
		{
			//绘制文字
			setbkmode(TRANSPARENT);//设置文字背景颜色透明
			settextcolor(RED);//设置文字颜色红色
			settextstyle(18, 0, "黑体");//设置文字大小,粗细,字体
			outtextxy(spr->x - textwidth(spr->name) / 2, spr->y - textheight(spr->y) / 2, spr->name);//绘制文字位置
		}
	}
}

//玩家移动
void MovePlayer(Sprite* spr,double dx,double dy)
{
	spr->x += dx;
	spr->y += dy;
}

//按键处理
void KeyDownDeal(Sprite* spr)
{
	int speed = 2;
	if (GetAsyncKeyState(VK_LEFT) && spr->x >= spr->r)
	{
		MovePlayer(&player, -speed, 0);
	}
	if (GetAsyncKeyState(VK_RIGHT) && spr->x <= getwidth() - spr->r)
	{
		MovePlayer(&player, speed, 0);
	}
	if (GetAsyncKeyState(VK_UP) && spr->y >= spr->r)
	{
		MovePlayer(&player, 0, -speed);
	}
	if (GetAsyncKeyState(VK_DOWN) && spr->y <= getheight() - spr->r)
	{
		MovePlayer(&player, 0, speed);
	}
}

//创建食物头指针
void CreatFood()
{
	one_food = (Sprite*)malloc(sizeof(Sprite));
	if (one_food == NULL)
	{
		_exit(0);
	}
	one_food->next = NULL;
}

//增加食物并初始化
void AddFood()
{
	Sprite* pnew;
	pnew = (Sprite*)malloc(sizeof(Sprite));
	if (pnew == NULL)//创建未成功退出
	{
		_exit(0);
	}
	pnew->next = NULL;
	InitSprite(pnew, rand() % getwidth(), rand() % getheight(), 1 + rand() % 3);

	pnew->next = one_food->next;
	one_food->next = pnew;
}

//获得两圆距离
int collision(Sprite* spr1, Sprite* spr2)
{
	return sqrt(pow(spr1->x - spr2->x, 2) + (pow(spr1->y - spr2->y, 2)));
}

//吃食物长大
void EatFood(Sprite* spr)
{
	Sprite* ftp0;
	ftp0 = one_food->next;
	while (ftp0!=NULL)
	{
		if (ftp0->exist == false)
		{
			ftp0 = ftp0->next;
			continue;
		}
		
		if (ftp0->exist == true && collision(spr, ftp0) < (spr->r+ftp0->r))
		{
			ftp0 ->exist = false;
			spr->r += ftp0->r / 8;
		}
		ftp0 = ftp0->next;
	}
}

//重新刷新食物
void RefreshFood()
{
	Sprite* ftp;
	ftp = one_food->next;
	while (ftp!=NULL)
	{
		if (ftp->exist == false)
		{
			InitSprite(ftp, rand() % getwidth(), rand() % getheight(), 1 + rand() % 3);
		}
		ftp = ftp->next;
	}
}

//创建ai玩家头指针
void CreatAIplayer()
{
	one_aiplayer = (Sprite*)malloc(sizeof(Sprite));
	if (one_aiplayer == NULL)
		_exit(0);
	one_aiplayer->next = NULL;
}

//添加ai玩家
void AddAIplayer(int num)
{
	Sprite* aitp;
	aitp = (Sprite*)malloc(sizeof(Sprite));
	if (aitp == NULL)
	{
		_exit(0);
	}
	aitp->next = NULL;
	InitSprite(aitp, rand() % getwidth(), rand() % getheight(), 10,names[num]);
	aitp->next = one_aiplayer->next;
	one_aiplayer->next = aitp;
}

2.3 ai玩家移动 ai玩家吃食物,ai与玩家和ai与ai之间进行互吃,ai追击目标(也可以自己写一个逃跑)

//判断是否玩家与ai玩家互吃,ai玩家互吃
void DevourEachOther()
{
	//判断玩家与ai玩家之间能否吃掉对方
	Sprite* aitemp1;
	aitemp1 = one_aiplayer->next;
	while (aitemp1 != NULL)
	{
		if (player.exist == true && aitemp1->exist == true && collision(&player, aitemp1) <= player.r&&player.r>=aitemp1->r*1.1)
		{
			aitemp1->exist = false;
			player.r += aitemp1->r / 8;
		}
		if (player.exist == true && aitemp1->exist == true && collision(&player, aitemp1) <= aitemp1->r&&player.r*1.1 <= aitemp1->r)
		{
			player.exist = false;
			aitemp1->r += player.r / 8;
		}
		//判断ai玩家之间是否能吃掉对方
		Sprite* aitemp2;
		aitemp2 = one_aiplayer->next;
		while (aitemp2!=NULL)
		{
			if (aitemp1 == aitemp2)
			{
				aitemp2 = aitemp2->next;
				continue;
			}
			if (aitemp2->exist == true && aitemp1->exist == true && collision(aitemp1, aitemp2) <= aitemp1->r&&aitemp1->r >= aitemp2->r*1.1)
			{
				aitemp2->exist = false;
				aitemp1->r += aitemp2->r / 8;
			}
			aitemp2 = aitemp2->next;
		}
		//判断ai玩家吃食物
		EatFood(aitemp1);
		aitemp1 = aitemp1->next;
	}
}

//追击目标
void chase(Sprite* run, Sprite* chase)
{
	if (run->x > chase->x)
	{
		chase->x++;
	}
	else
	{
		chase->x--;
	}
	if (run->y > chase->y)
	{
		chase->y++;
	}
	else
	{
		chase->y--;
	}
}

//判断两个精灵距离是否符合要求
bool SpriteOfRelation(Sprite* spr1,Sprite* spr2)
{
	int index_distance = 100;//目标在最小范围才去追击
	if (spr2->exist == true && spr1->r > spr2->r*1.5&&collision(spr1,spr2)<=index_distance)
	{
		return true;
	}
	return false;
}

//ai玩家找最近的食物
void FandFoods(Sprite* spr)

{
	Sprite* fw;//食物 指针
	fw = one_food->next;
	int min_distance = getheight();//ai玩家与食物最小距离
	while (fw != NULL)
	{
		if (fw->exist == true)
		{
			if (collision(spr, fw) < min_distance)
			{
				min_distance = collision(spr, fw);
				spr->food_index = fw;
			}
		}
		fw = fw->next;
	}
}
//ai玩家移动
void AiplayersMove()
{
	
	Sprite* aimp1 = one_aiplayer->next;//搜索每一个ai玩家
	while (aimp1 != NULL)
	{
		if (aimp1->exist)
		{
			//寻找合适的ai玩家目标
			Sprite* aimp2;
			aimp2 = one_aiplayer->next;
			while (aimp2 != NULL)
			{
				if (aimp1 == aimp2)
				{
					aimp2 = aimp2->next;
					continue;
				}
				if (SpriteOfRelation(aimp1, aimp2))
				{
					aimp1->food_index = aimp2;//当发现目标时将目标存入在标记中
				}

				aimp2 = aimp2->next;
			}
			
			//判断能否将玩家作为目标
			if (SpriteOfRelation(aimp1, &player))
			{
				aimp1->food_index = &player;
			}
			//追击目标必须存在且被追击的目标半径必须小于追击者的半径
			if (aimp1->food_index != NULL&&aimp1->food_index->exist == true && aimp1->food_index->r < aimp1->r)//如果标记目标,就追击目标
			{
				chase(aimp1->food_index, aimp1);
			}
			else
			{
				FandFoods(aimp1);//如果没有其他ai玩家目标,就找小食物
				chase(aimp1->food_index, aimp1);
			}
		}
		aimp1 = aimp1->next;
	}
}

2.4 从大到小排序 进行实时排名显示(没有把玩家加入排名,可以自行添加)

//从大到小排序
void sort()
{
	Sprite* p1 = one_aiplayer;//定义第一个结点
	Sprite* p2 = NULL;//下一个结点
	Sprite* tempt = NULL;//临时结点位置存放点
	Sprite* p3 = NULL;//用于存放临时最大数的上一个结点
	while (p1->next != NULL)
	{
		p2 = p1->next;
		tempt = p2;
		p3 = p1;
		while (p2 != NULL)
		{
			//将P2的半径与临时暂存半径进行比较,大的保存在tempt临时指针里
			if (tempt->r < p2->r)
			{
				tempt = p2;
			}
			p2 = p2->next;
		}

		while (p3->next != tempt)
		{
			p3 = p3->next;
		}

		p3->next = tempt->next;
		tempt->next = p1->next;
		p1->next = tempt;
		p1 = p1->next;
	}
}

//排名显示
void ranking() 
{
	Sprite* r;
	r = one_aiplayer->next;
	int i = 0;
	while (r!=NULL)
	{
		
		settextcolor(RGB(255 - i * 5, 215 - i * 10, 0 + i * 10));
		setbkmode(TRANSPARENT);
		settextstyle(20, 0, "黑体");
		char ch[60] = {0};
		sprintf(ch, "第%d名:%s", i+1, r->name);
		outtextxy(WIDTH - 250, i * 30 + 20, ch);
		i = i % 10;
		i++;
		r = r->next;
	}
}
 3. 其他模块

3.1 菜单界面 包括开始游戏,退出游戏,以及说明(以及返回)

//开始初始化界面菜单UI
void InitUI()
{

	//一级菜单
	initgraph(WIDTH, HEIGHT);//初始化窗口
	setbkcolor(GREEN);
	cleardevice();
	//游戏名
	char GameName[20] = { "球球大作战" };
	settextcolor(BLUE);
	settextstyle(60, 20, "黑体");
	outtextxy(WIDTH / 2 - textwidth(GameName) / 2, 50, GameName);

	//三个选项的背景
	fillrectangle(430, 200, 580, 260);
	fillrectangle(430, 300, 580, 360);
	fillrectangle(430, 400, 580, 460);

	setbkmode(TRANSPARENT);

	settextstyle(40, 10, "黑体");
	settextcolor(BLACK);

	//三个选项
	char select1[10] = { "开始游戏" };
	char select2[10] = { "退出游戏" };
	char select3[10] = { "游戏说明" };

	outtextxy(430 + textwidth(select1) / 2, 200 + textheight(select1) / 2, select1);
	outtextxy(430 + textwidth(select2) / 2, 300 + textheight(select2) / 2, select2);
	outtextxy(430 + textwidth(select3) / 2, 400 + textheight(select3) / 2, select3);
}

//菜单运行
int game_menu()
{
	InitUI();
	//BeginBatchDraw();
	MOUSEMSG m1;
	while (true)
	{
		m1 = GetMouseMsg();//获取鼠标操作
		if (m1.x >= 430 && m1.x <= 580 && m1.y >= 200 && m1.y <= 260)//游戏开始界面
		{
			setlinecolor(RED);
			rectangle(430, 200, 580, 260);
			if (m1.uMsg == WM_LBUTTONDOWN)
			{
				InitData();
				while (true)
				{
					//运行游戏
					BeginBatchDraw();//双缓冲绘图
					cleardevice();//在每次绘制之前清空屏幕
					DrawImg();
					KeyDownDeal(&player);
					EatFood(&player);
					RefreshFood();
					AiplayersMove();
					DevourEachOther();
					ranking();
					sort();
					EndBatchDraw();
				}
			}
		}
		else if (m1.x >= 430 && m1.x <= 580 && m1.y >= 300 && m1.y <= 360)
		{
			setlinecolor(RED);
			rectangle(430, 300, 580, 360);
			if (m1.uMsg == WM_LBUTTONDOWN)
			{
				closegraph();
				_exit(0);
			}
			
		}
		else if (m1.x >= 430 && m1.x <= 580 && m1.y >= 400 && m1.y <= 460)
		{
			setlinecolor(RED);
			rectangle(430, 400, 580, 460);
			if (m1.uMsg == WM_LBUTTONDOWN)
			{

				//二级菜单
				setbkcolor(WHITE);
				cleardevice();
				settextcolor(BLACK);
				settextstyle(20, 0, "黑体");
				setfillcolor(YELLOW);
				fillrectangle(40, 60, 140, 100);


				setbkmode(TRANSPARENT);
				char returna[20] = { "返回上一层" };
				outtextxy(40 +(50 - textwidth(returna) / 2), 60 + textheight(returna) / 2, returna);

				outtextxy(200, 100, "感谢大家的支持,有不足之处,请多多指正 ,请使用方向键,控制方向!!");

				MOUSEMSG m2;//第二层使用鼠标

				while (true)
				{
					m2 = GetMouseMsg();
					if (m2.x >= 40 && m2.x <= 140 && m2.y >= 60 && m2.y <= 100)//游戏开始界面

					{
						setlinecolor(RED);
						rectangle(40, 60, 140, 100);
						if (m2.uMsg == WM_LBUTTONDOWN)
						{
							closegraph();
							InitUI();
							break;
						}
					}
					else
					{
						setlinecolor(YELLOW);
						rectangle(40, 60, 140, 100);
					}	
				}
			}
		}
		else
		{
			setlinecolor(WHITE);
			rectangle(430, 200, 580, 260);
			rectangle(430, 300, 580, 360);
			rectangle(430, 400, 580, 460);
		}
	}
}

 3.2 主函数人口 内容不是太多,可以自行添加

//主窗口
int main()
{
	game_menu();
	closegraph();
	return 0;
}

 

转载请注明:文章转载自 www.wk8.com.cn
本文地址:https://www.wk8.com.cn/it/1038275.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 wk8.com.cn

ICP备案号:晋ICP备2021003244-6号