vs2022+easyx图形库实现简单植物大战僵尸

这是跟着b站rock老师写的代码,一个简易版的植物大战僵尸。

然后可以实现阳光生产 自动回收 登入界面还有过场动画 。

有三种植物向日葵,豌豆和食人花。

可以随机生成普通僵尸,豌豆会进行射击,向日葵也会生成阳光。

缺点是只有三种植物,目前还没有实现食人花吃僵尸的动作,bug是僵尸碰见食人花就消失了 然后食人花过一会也消失了,属于同归于尽了。而且阳光可以无限贷款,就是阳光不够会变成负数,这个我没有调整,而且没有设置关卡,只能一直打打打。也没有小推车,但是不管怎么说,也是自己一个一个敲出来的第一个正经实战项目,话不多看看效果。

植物大战僵尸

下面展示一下代码

main.cpp

#include"tools.h"


bool fileExist(const char* name)
{
	FILE* fp = fopen(name, "r");
	if(fp==NULL)
	{
		return false;
	}
	else
	{
		fclose(fp);
		return true;
	}
}

void gameInit()
{
	//加载有背景图片
	loadimage(&imgBg, "res/bg.jpg");
	loadimage(&imgBar, "res/bar5.png");

	memset(imgZhiWu, 0, sizeof(imgZhiWu));
	memset(map, 0, sizeof(map));
	//初始化植物卡牌
	char name[64];
	for ( int i = 0;  i < ZHI_WU_COUNT;  i++)
	{
		sprintf_s(name, sizeof(name), "res/Cards/card_%d.png", i + 1);//生成植物卡牌的文件名
		loadimage(&imageCards[i], name);
		for (int j = 0; j < 20; j++)
		{
			sprintf_s(name, sizeof(name), "res/zhiwu/%d/%d.png", i,j+1);
			//先判断这个文件是否存在
			if (fileExist(name))
			{
				imgZhiWu[i][j] = new IMAGE;
				loadimage(imgZhiWu[i][j], name);
			}
			else
			{
				break;
			}
		}
	}
	curZhiWu = 0;
	sunshine = 50;

	memset(balls, 0, sizeof(balls));
	for (int i = 0; i < 29; i++)
	{
		sprintf_s(name, sizeof(name), "res/sunshine/%d.png", i + 1);
		loadimage(&imgSunshineBall[i], name);
	}

	srand(time(NULL));//配置随机种子

	//创建游戏的图形窗口
	initgraph(WIN_WIDTH, WIN_HEIGHT);//1的意思是运行保存一个控制台

	LOGFONT f;//设置字体
	gettextstyle(&f);
	f.lfHeight = 30;
	f.lfWeight = 15;
	strcpy(f.lfFaceName, "Segoe UI Black");
	f.lfQuality = ANTIALIASED_QUALITY;//抗锯齿效果
	settextstyle(&f);
	setbkmode(TRANSPARENT);//字体透明
	setcolor(BLACK);//文本颜色

	memset(zms, 0, sizeof(zms));//初始化僵尸数据
	for (int i = 0; i < 22; i++)
	{
		sprintf_s(name, sizeof(name), "res/zm/%d.png", i + 1);
		loadimage(&imgZM[i], name);
	}

	loadimage(&imgBulletNormal, "res/bullets/bullet_normal.png");
	memset(bullets, 0, sizeof(bullets));

	//初始化豌豆子弹的帧图片数组
	loadimage(&imgBullBlast[3], "res/bullets/bullet_blast.png");
	for(int i=0;i<3;i++)
	{
		float k = (i + 1) * 0.2;
		loadimage(&imgBullBlast[i], "res/bullets/bullet_blast.png", imgBullBlast[3].getwidth() * k, imgBullBlast[3].getheight() * k,true);
	}

	for (int i = 0; i < 20; i++)//初始化僵尸死亡
	{
		sprintf_s(name, sizeof(name), "res/zm_dead/%d.png", i+1);
		loadimage(&imgZMDead[i], name);
	}

	for (int i = 0; i < 21; i++)//初始化僵尸吃植物
	{
		sprintf_s(name,"res/zm_eat/%d.png", i + 1);
		loadimage(&imgZMEat[i], name);
	}
	for (int i = 0; i < 11; i++)//初始化僵尸站立
	{
		sprintf_s(name, "res/zm_stand/%d.png", i + 1);
		loadimage(&imgZmStand[i], name);
	}
	for (int i = 0; i < 4; i++)
	{
		sprintf_s(name, sizeof(name), "res/zhiwu_eat/%d.png", i + 1);
		loadimage(&imgeating[i], name);
	}
}




void userClick()
{
	ExMessage msg;
	static int status = 0;
	if (peekmessage(&msg))
	{
		if (msg.message == WM_LBUTTONDOWN)//鼠标点击
		{
			if (msg.x > 338 && msg.x < 338 + 65 * ZHI_WU_COUNT && msg.y < 96)
			{
				int index = (msg.x - 338) / 65;
				status = 1;
				curZhiWu = index + 1;
			}
			else
			{
				collectSunshine(&msg);
			}
		}
		else if (msg.message == WM_MOUSEMOVE && status == 1)//鼠标拖动
		{
			curX = msg.x;
			curY = msg.y;
		}
		else if(msg.message==WM_LBUTTONUP && status == 1)//鼠标松开种植物
		{
			if(msg.x>256-112&&msg.y>179&&msg.y<489)
			{
				int row = (msg.y - 179) / 102;
				int col = (msg.x - (256 - 112)) / 81;
				if(map[row][col].type==0)
				{
					
					map[row][col].type = curZhiWu;
					map[row][col].frameIndex = 0;
					if (map[row][col].type == SHI_REN_HUA+1)
					{
						map[row][col].x = 256 - 122 + col * 81;
						map[row][col].y = 179 + row * 102  -15;
					}
					else
					{
						map[row][col].x = 256 - 112 + col * 81;
						map[row][col].y = 179 + row * 102 + 14;
					}

				}
				if (map[row][col].type == WAN_DOU+1)//种植的是豌豆
				{
					sunshine -= 100;
				}
				else if(map[row][col].type==XIANG_RI_KUI+1)//种植的是向日葵
				{
					sunshine -= 50;
				}
				else if (map[row][col].type == SHI_REN_HUA + 1)
				{
					sunshine -= 150;
				}
			}
			curZhiWu = 0;
			status = 0;
		}
	}
}

void updateWindow()//更新窗口
{
	BeginBatchDraw();//开始缓冲
	putimage(-112, 0, &imgBg);
	//putimage(250, 0, &imgBar);
	putimagePNG(250, 0, &imgBar);
	drawcard();
	drawZhiWu();
	drawSunshine();

	drawZm();//绘制僵尸

	int bulletMax = sizeof(bullets) / sizeof(bullets[0]);//渲染子弹
	for (int i = 0; i < bulletMax; i++)
	{
		if (bullets[i].used)
		{
			if (bullets[i].blast)
			{
				IMAGE* img = &imgBullBlast[bullets[i].frameIndex];
				putimagePNG(bullets[i].x, bullets[i].y, img);
			}
			else
			{
				putimagePNG(bullets[i].x, bullets[i].y, &imgBulletNormal);
			}
		}
	}

	EndBatchDraw();//结束缓冲
}

void updateGame()
{
	updateZhiWu();//更新植物
	createSunshine();//创建阳光
	updateSunshine();//更新阳光的状态
	
	createZM();//创建僵尸
	updateZM();//更新僵尸

	shoot();//发射子弹
	updateBullets();//更新子弹

	collisionCheck();//实现碰撞检测
}

void startUI()
{
	IMAGE imgBg, imgMenu1, imgMenu2;
	loadimage(&imgBg, "res/menu.png");
	loadimage(&imgMenu1, "res/menu1.png");
	loadimage(&imgMenu2, "res/menu2.png");
	int flag = 0;
	while(1)
	{
		BeginBatchDraw();
		putimage(0, 0, &imgBg);
		putimagePNG(475, 75, flag ? &imgMenu2 : &imgMenu1);
		ExMessage msg;
		if(peekmessage(&msg))
		{
			if (msg.message == WM_LBUTTONDOWN && msg.x > 474 && msg.x < 474 + 300 && msg.y>75 && msg.y < 75 + 140)
			{
				flag = 1;
			}
			else if(msg.message==WM_LBUTTONUP&&flag==1)
			{
				EndBatchDraw();
				break;
			}
		}
		EndBatchDraw();
	}
}
void viewScence()
{
	int xMin = WIN_WIDTH - imgBg.getwidth();
	vector2 point[9] = {
		{550,80},{530,160},{630,170},{530,200},{515,270},{565,370},{605,340},{705,280},{690,340}
	};
	int index[9];
	mciSendString("play res/bg.mp3", 0, 0, 0);

	for (int i= 0; i <9; i++)
	{
		index[i] = rand() % 11;
	}

	for (int x = 0; x >= xMin; x-=2)
	{
		BeginBatchDraw();
		putimage(x, 0, &imgBg);

	for (int k = 0; k < 9; k++)
		{
			putimagePNG(point[k].x - xMin + x,point[k].y,&imgZmStand[index[k]]);
			index[k] = (index[k] + 1) % 11;
		}

		EndBatchDraw();
		Sleep(10);
	}
	for(int i=0;i<100;i++)
	{
		BeginBatchDraw();
		putimage(xMin, 0, &imgBg);
		for (int k = 0; k < 9; k++)
		{
			putimagePNG(point[k].x, point[k].y, &imgZmStand[index[k]]);
			index[k] = (index[k] + 1) % 11;
		}
		EndBatchDraw();
		Sleep(10);
	}
	for (int x = xMin; x < -112; x += 2)
	{
		BeginBatchDraw();
		putimage(x, 0, &imgBg);
		for (int k = 0; k < 9; k++)
		{
			putimagePNG(point[k].x - xMin + x, point[k].y, &imgZmStand[index[k]]);
			index[k] = (index[k] + 1) % 11;

		}
		EndBatchDraw();
		Sleep(10);
	}
}
int main(void)
{
	gameInit();
	startUI();

	viewScence();//转场
	int timer = 0;
	bool flag = true;
	while(1)
	{
		userClick();
		timer += getDelay();
		if(timer>10)
		{
			flag = true;
			timer = 0;
		}
		if(flag)
		{
			flag = false;
			updateWindow();
			updateGame();
		}
	}
	while (1);
	return 0;
}

yang_guang.cpp

#include"tools.h"
struct sunshineBall balls[10];
IMAGE imgSunshineBall[29];
int sunshine;


void createSunshine()//创建阳光
{
	static int count = 0;
	static int fre = 100;
	count++;
	if (count >= fre)
	{
		fre = 200 + rand() % 200;
		count = 0;

		int ballMax = sizeof(balls) / sizeof(balls[0]);//从阳光池里取一个可以用的
		int i;
		for (i = 0; i < ballMax && balls[i].used; i++);
		if (i >= ballMax) return;
		balls[i].used = true;
		balls[i].frameIndex = 0;
		balls[i].timer = 0;
		balls[i].status = SUNSHINE_DOWN;
		balls[i].t = 0;
		balls[i].p1 = vector2(260 + rand() % (900 - 260), 60);
		balls[i].p4 = vector2(balls[i].p1.x, 200 + (rand() % 4) * 90);
		int off = 2;
		float distance = balls[i].p4.y - balls[i].p1.y;
		balls[i].speed = 1.0 / (distance / off);
	}
	int ballMax = sizeof(balls) / sizeof(balls[0]);//向日葵生产阳光
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 9; j++)
		{
			if (map[i][j].type == XIANG_RI_KUI + 1)
			{
				map[i][j].timer++;
				if (map[i][j].timer > 200)
				{
					map[i][j].timer = 0;
					int k;
					for (k = 0; k < ballMax && balls[k].used; k++);
					if (k >= ballMax) return;

					balls[k].used = true;
					balls[k].p1 = vector2(map[i][j].x, map[i][j].y);
					int w = (100 + rand() % 50) * (rand() % 2 ? 1 : -1);
					balls[k].p4 = vector2(map[i][j].x + w, map[i][j].y + imgZhiWu[XIANG_RI_KUI][0]->getheight() -
						imgSunshineBall[0].getheight());
					balls[k].p2 = vector2(balls[k].p1.x + w * 0.3, balls[k].p1.y - 100);
					balls[k].p3 = vector2(balls[k].p1.x + w * 0.7, balls[k].p1.y - 100);
					balls[k].status = SUNSHINE_RPODUCT;
					balls[k].speed = 0.05;
					balls[k].t = 0;
				}
			}
		}
	}
}

void updateSunshine()//更新阳光
{
	int ballMax = sizeof(balls) / sizeof(balls[0]);
	for (int i = 0; i < ballMax; i++)
	{
		if (balls[i].used)
		{
			balls[i].frameIndex = (balls[i].frameIndex + 1) % 29;
			if (balls[i].status == SUNSHINE_DOWN)
			{
				struct sunshineBall* sun = &balls[i];
				sun->t += sun->speed;
				sun->pCur = sun->p1 + sun->t * (sun->p4 - sun->p1);
				if (sun->t >= 1)
				{
					sun->status = SUNSHINE_GROUND;
					sun->timer = 0;
				}
			}
			else if (balls[i].status == SUNSHINE_GROUND)
			{
				balls[i].timer++;
				if (balls[i].timer > 100)
				{
					balls[i].p1 = balls[i].pCur;//起点
					balls[i].p4 = vector2(262, 0);//终点
					float distance = dis(balls[i].p1 - balls[i].p4);
					float off = 8;
					balls[i].speed = 1.0 / (distance / off);
					balls[i].t = 0;
					balls[i].status = SUNSHINE_COLLECT;
					break;;
				}
			}
			else if (balls[i].status == SUNSHINE_COLLECT)
			{
				struct sunshineBall* sun = &balls[i];
				sun->t += sun->speed;
				sun->pCur = sun->p1 + sun->t * (sun->p4 - sun->p1);
				if (sun->t > 1)
				{
					sun->used = false;
					sunshine += 25;
				}
			}
			else if (balls[i].status == SUNSHINE_RPODUCT)
			{
				struct sunshineBall* sun = &balls[i];
				sun->t += sun->speed;
				sun->pCur = calcBezierPoint(sun->t, sun->p1, sun->p2, sun->p3, sun->p4);
				if (sun->t > 1)
				{
					sun->status = SUNSHINE_GROUND;
					sun->timer = 0;
				}
			}

		}
	}
}

void drawSunshine()//绘制阳光,更新分数
{
	int ballMax = sizeof(balls) / sizeof(balls[0]);
	for (int i = 0; i < ballMax; i++)
	{
		if (balls[i].used)
		{
			IMAGE* img = &imgSunshineBall[balls[i].frameIndex];
			putimagePNG(balls[i].pCur.x, balls[i].pCur.y, img);
		}
	}
	char scoreText[8];
	sprintf_s(scoreText, sizeof(scoreText), "%d", sunshine);
	outtextxy(276, 67, scoreText);//输出分数
}
void collectSunshine(ExMessage* msg)//收集阳光
{
	int count = sizeof(balls) / sizeof(balls[0]);
	int w = imgSunshineBall[0].getwidth();
	int h = imgSunshineBall[0].getheight();
	for (int i = 0; i < count; i++)
	{
		if (balls[i].used)
		{

			int x = balls[i].pCur.x;
			int y = balls[i].pCur.y;
			if (msg->x > x && msg->x < x + w && msg->y > y && msg->y < y + h)
			{

				balls[i].status = SUNSHINE_COLLECT;
				PlaySound("res/sunshine.wav", NULL, SND_FILENAME | SND_ASYNC);
				balls[i].p1 = balls[i].pCur;//起点
				balls[i].p4 = vector2(262, 0);//终点
				float distance = dis(balls[i].p1 - balls[i].p4);
				float off = 8;
				balls[i].speed = 1.0 / (distance / off);
				balls[i].t = 0;
				break;

			}
		}
	}
}

我展示的分别是主函数和阳光部分代码,然后其它的后续我会上传到资源里面,如果需要图片音乐文件可以私信我,或者和我一起讨论代码 完成整个游戏过程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值